How to Create a Blazor WebAssembly Application with Prerendering
29 Nov 20249 minutes to read
This section explains how to enable prerendering to a Blazor WebAssembly application.
Prerequisites
.NET 7.0 or later.
Create a new project for Blazor WebAssembly ASP.NET Core Hosted application
-
Create a new Blazor WebAssembly ASP.NET Core Hosted application.
-
Delete
~/wwwroot/index.html
file in the Client project. -
Remove the below line from Client project’s
~/Program.cs
file.// builder.RootComponents.Add<App>("#app");
-
Add
~/Pages/_Host.cshtml
file in the Server project. -
Copy and paste the below code content in the
~/Server/Pages/_Host.cshtml
file.@page "/" @namespace BlazorWebAssemblyHosted.Client.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>BlazorWebAssemblyHosted</title> <base href="~/" /> <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /> <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" /> <link href="css/app.css" rel="stylesheet" /> <link href="BlazorWebAssemblyHosted.Client.styles.css" rel="stylesheet" /> <link href="_content/Syncfusion.Blazor.Themes/bootstrap4.css" rel="stylesheet" /> </head> <body> <component type="typeof(App)" render-mode="WebAssemblyPrerendered" /> <script src="_framework/blazor.webassembly.js"></script> </body> </html>
-
Open
Program.cs
file in the Server project and change endpoint ofMapFallbackToFile
configuration fromindex.html
to/_Host
..... app.UseEndpoints(endpoints => { .... .... endpoints.MapFallbackToFile("/_Host"); // Previously it was mapped into "index.html". });
-
Add Syncfusion® Blazor service in the
~/Server/Program.cs
file.using Syncfusion.Blazor; .... builder.Services.AddSyncfusionBlazor();
-
If you don’t inject and use
HttpClient
DI on your index page, you can run the application and the component will render in the web browser with prerendering mode.The created Blazor WebAssembly ASP.NET Core Hosted application has injected the
HttpClient
DI and fetch the data from server for SfGrid component data source. So, refer to the next topic to resolve theHttpClient
error on prerendering mode.
Resolving HttpClient errors on WebAssembly prerendering
When the index page is injected with the HttpClient
and tried to prerender on the server, the client will not establish its connection at that time. So, it will throw the runtime exceptions.
ERROR
InvalidOperationException: An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.
The Syncfusion® Blazor service has registered the HttpClient service itself by default. When you run the WebAssemblyPrerendered
mode application, it tries to get the WebAPI with its absolute URI or BaseAddress.
If you configure with absolute URI in the ~/Client/Pages/Index.razor
file, you will face another runtime error.
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("http://localhost:44376/WeatherForecast");
}
ERROR
SocketException: An existing connection was forcibly closed by the remote host.
IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host
HttpRequestException: An error occurred while sending the request.
We are trying to use HTTP from Server to get the fetch data. But, it is also not possible in the prerender mode because of the client is not yet established.
Refer to the below steps to resolve these issues and make the app running with HttpClient in the prerendering mode.
-
Create a public interface in the
~/Shared/WeatherForecast.cs
file on the Shared project to abstract the API call.using System.Threading.Tasks; public interface IWeatherForecastService { Task<WeatherForecast[]> GetForecastAsync(); }
-
Create a class file
~/Client/Shared/WeatherForecastService.cs
and inherit the class with the new interfaceIWeatherForecastService
. Here, the override methodGetForecastAsync
will fetch the data using HTTP Get action.using System.Net.Http; using System.Net.Http.Json; using System.Threading.Tasks; using BlazorWebAssemblyHosted.Shared; namespace BlazorWebAssemblyHosted.Client.Shared { public class WeatherForecastService : IWeatherForecastService { private readonly HttpClient httpClient; public WeatherForecastService(HttpClient http) { httpClient = http; } public async Task<WeatherForecast[]> GetForecastAsync() { return await httpClient.GetFromJsonAsync<WeatherForecast[]> ("WeatherForecast"); } } }
-
create a new class file with same class name on the Server project and inherit with the interface
IWeatherForecastService
. Here, the existing API~/Server/Controller/WeatherForecastController.cs
data creation process moved into the override methodGetForecastAsync
.using System; using System.Linq; using System.Threading.Tasks; using BlazorWebAssemblyHosted.Shared; namespace BlazorWebAssemblyHosted.Server.Shared { public class WeatherForecastService : IWeatherForecastService { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; public async Task<WeatherForecast[]> GetForecastAsync() { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }).ToArray(); } } }
-
Now, the API controller will have the below changes on
~/Server/Controller/WeatherForecastController.cs
file.using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using BlazorWebAssemblyHosted.Shared; namespace BlazorWebAssemblyHosted.Server.Controllers { [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private readonly IWeatherForecastService weatherForecastService; public WeatherForecastController(IWeatherForecastService weatherService) { weatherForecastService = weatherService; } [HttpGet] public async Task<IEnumerable<WeatherForecast>> Get() { return await weatherForecastService.GetForecastAsync(); } } }
-
Register the services in both Client and Server project
~/Program.cs
file..... using Syncfusion.Blazor; .... builder.Services.AddSyncfusionBlazor();
-
Now, change the DI injection from
HttpClient
toIWeatherForecastService
on the~/Client/Pages/Index.razor
file.@using BlazorWebAssemblyHosted.Shared @inject IWeatherForecastService WeatherForecastService .... .... @code { private WeatherForecast[] forecasts; protected override async Task OnInitializedAsync() { forecasts = await WeatherForecastService.GetForecastAsync(); } }
-
Run the application by pressing
F5
key. The Server prerendering will get the data from its local service, and when it renders on the Client, the HTTP Get request will be sent to get the data.