Skip to content

Example project showing how to implement prerendering in Blazor client side application

Notifications You must be signed in to change notification settings

RasmusTG/blazor-client-prerender

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

BlazorClientPrerender

This example demonstrates one of the ways to achive client side blazor prerendering (sometimes known as Server side rendering).

Prerendering is very important for public SPA applications because of its impact on SEO and initial page load time.

Project structure description

  • BlazorClientPrerender.Shared - Shared DTO definitions and service interfaces for server side and client side logic
  • BlazorClientPrerender.Service - Server side service implementations - used by server side blazor and our REST API
  • BlazorClientPrerender.Api - Our REST API that our client side blazor project will talk to
  • BlazorClientPrerender.Client - Client side blazor project
  • BlazorClientPrerender.Startup - Blazor server side rendering project and the one we will expose to the public

Running sample application:

Cmd:

cd BlazorClientPrerender.Api
dotnet run

cd BlazorClientPrerender.Client
dotnet run

cd BlazorClientPrerender.Startup
dotnet run

Open web browser at https://localhost:6001/

How it works

Our server side blazor project (BlazorClientPrerender.Startup) is rendering component described our client side blazor project on initial load and serves it from _Host.cshtml:

<body>
    <app>@(await Html.RenderComponentAsync<BlazorClientPrerender.Client.App>())</app>

    <!-- We replaced blazor.server.js with blazor.webassembly.js because we are going to use client side after initial render -->
    <script src="_framework/blazor.webassembly.js"></script>
    <!-- <script src="_framework/blazor.server.js"></script> -->
</body>

After the initial load blazor.webassembly.js will try to load mono.wasam and .dll files that run on mono and replace contents of our , to serve client-side dependencies properly we are proxying every request that comes to /_framework path to http://localhost:5000/ which exposes client side dependencies:

// Route _framework requests to client side generated .dlls 
// ( Our client side blazor is running on localhost:5000 )
app.MapWhen((context) => context.Request.Path.Value.StartsWith("/_framework"), 
	builder => builder.RunProxy(new ProxyOptions()
{
	Scheme = "http",
	Host = new HostString("localhost", 5000)
}));

Rendering the data:

Current approach (more reliable)

In our startup project we are registering HttpClient with DI, so that we can share client side implementation of our services for initial render (on the server) and for the client side data fetching.

// Register HttpClient, in dev mode we won't validate SSL certs because they are self signed
services.AddScoped<HttpClient>(s => 
{
	return Environment.IsDevelopment() ? 
		new HttpClient(new HttpClientHandler()
		{
			  ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
		}) : new HttpClient();
});

// Register custom services
services.AddScoped<IWeatherForecastService, WeatherForecastClientService>();

Old approach

Altough this approach is slightly faster for initial render (because we are calling our serverside logic directly instead of calling our logic through REST API, we could get different results if there is additional processing on the data after the service layer)

In this example we are injecting different implementations of IWeatherForecastService depending on project:

In our REST API and in our server side rendering Startup.cs we are registering server side implementation that can access server resources directly (ie. EF DbContext)

public void ConfigureServices(IServiceCollection services)
{
	...
	services.AddScoped<IWeatherForecastService, WeatherForecastService>();
}

And in our client side we are injecting implementation of service that is using HttpClient to talk to our REST API and access data:

public void ConfigureServices(IServiceCollection services)
{
	services.AddSingleton<IWeatherForecastService, WeatherForecastClientService>();
}

About

Example project showing how to implement prerendering in Blazor client side application

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 53.3%
  • HTML 25.8%
  • CSS 20.9%