Edit

Share via


Prerender ASP.NET Core Razor components

Note

This isn't the latest version of this article. For the current release, see the .NET 9 version of this article.

Important

This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

For the current release, see the .NET 9 version of this article.

This article explains Razor component prerendering scenarios for server-rendered components in Blazor Web Apps and Blazor Server apps.

Prerendering is the process of statically rendering page content from the server to deliver HTML to the browser as quickly as possible. After the prerendered content is quickly displayed to the user, interactive content with active event handlers are rendered, replacing any content that was rendered previously. Prerendering can also improve Search Engine Optimization (SEO) by rendering content for the initial HTTP response that search engines use to calculate page rank.

Prerendering is enabled by default for interactive components.

Internal navigation for interactive routing doesn't involve requesting new page content from the server. Therefore, prerendering doesn't occur for internal page requests, including for enhanced navigation. For more information, see Static versus interactive routing, Interactive routing and prerendering, and Enhanced navigation and form handling.

OnAfterRender{Async} component lifecycle events aren't called when prerendering, only after the component renders interactively.

Disable prerendering

Prerendering can complicate an app because the app's Razor components must render twice: once for prerendering and once for setting up interactivity. If the components are set up to run on WebAssembly, then you also must design your components so that they can run from both the server and the client.

To disable prerendering for a component instance, pass the prerender flag with a value of false to the render mode:

  • <... @rendermode="new InteractiveServerRenderMode(prerender: false)" />
  • <... @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
  • <... @rendermode="new InteractiveAutoRenderMode(prerender: false)" />

To disable prerendering in a component definition:

  • @rendermode @(new InteractiveServerRenderMode(prerender: false))
  • @rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
  • @rendermode @(new InteractiveAutoRenderMode(prerender: false))

To disable prerendering for the entire app, indicate the render mode at the highest-level interactive component in the app's component hierarchy that isn't a root component.

For apps based on the Blazor Web App project template, a render mode assigned to the entire app is specified where the Routes component is used in the App component (Components/App.razor). The following example sets the app's render mode to Interactive Server with prerendering disabled:

<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />

Also, disable prerendering for the HeadOutlet component in the App component:

<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />

Making a root component, such as the App component, interactive with the @rendermode directive at the top of the root component's definition file (.razor) isn't supported. Therefore, prerendering can't be disabled directly by the App component.

Disabling prerendering using the preceding techniques only takes effect for top-level render modes. If a parent component specifies a render mode, the prerendering settings of its children are ignored.

Persist prerendered state

Without persisting prerendered state, state used during prerendering is lost and must be recreated when the app is fully loaded. If any state is created asynchronously, the UI may flicker as the prerendered UI is replaced when the component is rerendered. For guidance on how to persist state during prerendering, see ASP.NET Core Blazor prerendered state persistence.

Client-side services fail to resolve during prerendering

Assuming that prerendering isn't disabled for a component or for the app, a component in the .Client project is prerendered on the server. Because the server doesn't have access to registered client-side Blazor services, it isn't possible to inject these services into a component without receiving an error that the service can't be found during prerendering.

For example, consider the following Home component in the .Client project in a Blazor Web App with global Interactive WebAssembly or Interactive Auto rendering. The component attempts to inject IWebAssemblyHostEnvironment to obtain the environment's name.

@page "/"
@inject IWebAssemblyHostEnvironment Environment

<PageTitle>Home</PageTitle>

<h1>Home</h1>

<p>
    Environment: @Environment.Environment
</p>

No compile time error occurs, but a runtime error occurs during prerendering:

Cannot provide a value for property 'Environment' on type 'BlazorSample.Client.Pages.Home'. There is no registered service of type 'Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment'.

This error occurs because the component must compile and execute on the server during prerendering, but IWebAssemblyHostEnvironment isn't a registered service on the server.

If the app doesn't require the value during prerendering, this problem can be solved by injecting IServiceProvider to obtain the service instead of the service type itself:

@page "/"
@using Microsoft.AspNetCore.Components.WebAssembly.Hosting
@inject IServiceProvider Services

<PageTitle>Home</PageTitle>

<h1>Home</h1>

<p>
    <b>Environment:</b> @environmentName
</p>

@code {
    private string? environmentName;

    protected override void OnInitialized()
    {
        if (Services.GetService<IWebAssemblyHostEnvironment>() is { } env)
        {
            environmentName = env.Environment;
        }
    }
}

If you merely want to make the service injection optional, you can use constructor injection:

private string? environmentName;

public Home(IWebAssemblyHostEnvironment? env = null)
{
    environmentName = env?.Environment;
}

Another option for obtaining the environment whether the code is running on the server or on the client is to inject IHostEnvironment from the Microsoft.Extensions.Hosting.Abstractions NuGet package. Add a package reference to the app and use the following approach:

private string? environmentName;

public Home(IHostEnvironment? serverEnvironment = null, 
    IWebAssemblyHostEnvironment? wasmEnvironment = null)
{
    environmentName = serverEnvironment?.EnvironmentName;
    environmentName ??= wasmEnvironment?.Environment;
}

You can also avoid the problem if you disable prerendering for the component, but that's an extreme measure to take in many cases that may not meet your component's specifications.

There are a four approaches that you can take to address this scenario for prerendering. The following are listed from most recommended to least recommended:

  • For shared framework services that merely aren't registered server-side in the main project, register the services in the main project, which makes them available during prerendering. For an example of this scenario, see the guidance for HttpClient services in the Blazor Web App external web APIs section of the Call web API article.

  • Make the service optional if it isn't always needed. See the first two examples in this section.

  • Create a service abstraction and create implementations for the service in the .Client and server projects. Register the services in each project. Inject the custom service abstraction in the component.

  • For services outside of the shared framework, create a custom service implementation for the service on the server. Use the service normally in interactive components of the .Client project. For a demonstration of this approach, see ASP.NET Core Blazor environments.

Prerendering guidance

Prerendering guidance is organized in the Blazor documentation by subject matter. The following links cover all of the prerendering guidance throughout the documentation set by subject:

For .NET 7 or earlier, see Blazor WebAssembly security additional scenarios: Prerendering with authentication. After viewing the content in this section, reset the documentation article version selector dropdown to the latest .NET release version to ensure that documentation pages load for the latest release on subsequent visits.