Prerender and integrate ASP.NET Core Razor components

By Luke Latham and Daniel Roth

Razor components can be integrated into Razor Pages and MVC apps in a hosted Blazor WebAssembly solution. When the page or view is rendered, components can be prerendered at the same time.

Configuration

To set up prerendering for a Blazor WebAssembly app:

  1. Host the Blazor WebAssembly app in an ASP.NET Core app. A standalone Blazor WebAssembly app can be added to an ASP.NET Core solution, or you can use a hosted Blazor WebAssembly app created from the Blazor Hosted project template.

  2. Remove the default static wwwroot/index.html file from the Blazor WebAssembly client project.

  3. Delete the following line in Program.Main in the client project:

    builder.RootComponents.Add<App>("#app");
    
  4. Add a Pages/_Host.cshtml file to the server project. You can obtain a _Host.cshtml file from an app created from the Blazor Server template with the dotnet new blazorserver -o BlazorServer command in a command shell. After placing the Pages/_Host.cshtml file into the server app of the hosted Blazor WebAssembly solution, make the following changes to the file:

    • Set the namespace to the server app's Pages folder (for example, @namespace BlazorHosted.Server.Pages).

    • Set an @using directive for the client project (for example, @using BlazorHosted.Client).

    • Update the stylesheet links to point to the WebAssembly app's stylesheet. In the following example, the client app's namespace is BlazorHosted.Client:

      <link href="css/app.css" rel="stylesheet" />
      <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
      
    • Update the render-mode of the Component Tag Helper to prerender the root App component:

      <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
      
    • Update the Blazor script source to use the client-side Blazor WebAssembly script:

      <script src="_framework/blazor.webassembly.js"></script>
      
  5. In Startup.Configure (Startup.cs) of the server project:

    • Call UseDeveloperExceptionPage on the app builder in the Development environment.
    • Call UseBlazorFrameworkFiles on the app builder.
    • Change the fallback from the index.html page (endpoints.MapFallbackToFile("index.html");) to the _Host.cshtml page.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseWebAssemblyDebugging();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }
    
        app.UseHttpsRedirection();
        app.UseBlazorFrameworkFiles();
        app.UseStaticFiles();
    
        app.UseRouting();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
            endpoints.MapControllers();
            endpoints.MapFallbackToPage("/_Host");
        });
    }
    

Render components in a page or view with the Component Tag Helper

The Component Tag Helper supports two render modes for rendering a component from a Blazor WebAssembly app in a page or view:

  • WebAssembly: Renders a marker for a Blazor WebAssembly app for use to include an interactive component when loaded in the browser. The component isn't prerendered. This option makes it easier to render different Blazor WebAssembly components on different pages.
  • WebAssemblyPrerendered: Prerenders the component into static HTML and includes a marker for a Blazor WebAssembly app for later use to make the component interactive when loaded in the browser.

In the following Razor Pages example, the Counter component is rendered in a page. To make the component interactive, the Blazor WebAssembly script is included in the page's render section. To avoid using the full namespace for the Counter component with the Component Tag Helper ({APP ASSEMBLY}.Pages.Counter), add an @using directive for the client app's Pages namespace. In the following example, the client app's namespace is BlazorHosted.Client:

...
@using BlazorHosted.Client.Pages

<h1>@ViewData["Title"]</h1>

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

RenderMode configures whether the component:

  • Is prerendered into the page.
  • Is rendered as static HTML on the page or if it includes the necessary information to bootstrap a Blazor app from the user agent.

For more information on the Component Tag Helper, including passing parameters and RenderMode configuration, see Component Tag Helper in ASP.NET Core.

The preceding example requires that the server app's layout (_Layout.cshtml) include a render section (RenderSection) for the script inside the closing </body> tag:

    ...

    @RenderSection("Scripts", required: false)
</body>

The _Layout.cshtml file is located in the Pages/Shared folder in a Razor Pages app or Views/Shared folder in an MVC app.

If the app should also style components with the styles in the Blazor WebAssembly app, include the app's styles in the _Layout.cshtml file. In the following example, the client app's namespace is BlazorHosted.Client:

<head>
    ...

    <link href="css/app.css" rel="stylesheet" />
    <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
</head>

Render components in a page or view with a CSS selector

Add root components to the Client project in Program.Main (Program.cs). In the following example, the Counter component is declared as a root component with a CSS selector that selects the element with the id that matches my-counter. In the following example, the client app's namespace is BlazorHosted.Client:

using BlazorHosted.Client.Pages;

...

builder.RootComponents.Add<Counter>("#my-counter");

In the following Razor Pages example, the Counter component is rendered in a page. To make the component interactive, the Blazor WebAssembly script is included in the page's render section:

...

<h1>@ViewData["Title"]</h1>

<div id="my-counter">Loading...</div>

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

The preceding example requires that the server app's layout (_Layout.cshtml) include a render section (RenderSection) for the script inside the closing </body> tag:

    ...

    @RenderSection("Scripts", required: false)
</body>

The _Layout.cshtml file is located in the Pages/Shared folder in a Razor Pages app or Views/Shared folder in an MVC app.

If the app should also style components with the styles in the Blazor WebAssembly app, include the app's styles in the _Layout.cshtml file. In the following example, the client app's namespace is BlazorHosted.Client:

<head>
    ...

    <link href="css/app.css" rel="stylesheet" />
    <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
</head>

Integrating Razor components into Razor Pages and MVC apps in a hosted Blazor WebAssembly solution is supported in ASP.NET Core in .NET 5 or later. Select a .NET 5 or later version of this article.

Razor components can be integrated into Razor Pages and MVC apps in a Blazor Server app. When the page or view is rendered, components can be prerendered at the same time.

After configuring the app, use the guidance in the following sections depending on the app's requirements:

Configuration

An existing Razor Pages or MVC app can integrate Razor components into pages and views:

  1. In the app's layout file (_Layout.cshtml):

    • Add the following <base> tag to the <head> element:

      <base href="~/" />
      

      The href value (the app base path) in the preceding example assumes that the app resides at the root URL path (/). If the app is a sub-application, follow the guidance in the App base path section of the Host and deploy ASP.NET Core Blazor article.

      The _Layout.cshtml file is located in the Pages/Shared folder in a Razor Pages app or Views/Shared folder in an MVC app.

    • Add a <script> tag for the blazor.server.js script immediately before the Scripts render section:

          ...
          <script src="_framework/blazor.server.js"></script>
      
          @await RenderSectionAsync("Scripts", required: false)
      </body>
      

      The framework adds the blazor.server.js script to the app. There's no need to manually add the script to the app.

  2. Add an _Imports.razor file to the root folder of the project with the following content (change the last namespace, MyAppNamespace, to the namespace of the app):

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.JSInterop
    @using MyAppNamespace
    
  3. In Startup.ConfigureServices, register the Blazor Server service:

    services.AddServerSideBlazor();
    
  4. In Startup.Configure, add the Blazor Hub endpoint to app.UseEndpoints:

    endpoints.MapBlazorHub();
    
  5. Integrate components into any page or view. For more information, see the Render components from a page or view section.

Use routable components in a Razor Pages app

This section pertains to adding components that are directly routable from user requests.

To support routable Razor components in Razor Pages apps:

  1. Follow the guidance in the Configuration section.

  2. Add an App.razor file to the project root with the following content:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    

    Note

    With the release of ASP.NET Core 5.0.1 and for any additional 5.x releases, the Router component includes the PreferExactMatches parameter set to true. For more information, see Migrate from ASP.NET Core 3.1 to 5.0.

  3. Add a _Host.cshtml file to the Pages folder with the following content:

    @page "/blazor"
    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    Components use the shared _Layout.cshtml file for their layout.

    RenderMode configures whether the App component:

    • Is prerendered into the page.
    • Is rendered as static HTML on the page or if it includes the necessary information to bootstrap a Blazor app from the user agent.

    For more information on the Component Tag Helper, including passing parameters and RenderMode configuration, see Component Tag Helper in ASP.NET Core.

  4. Add a low-priority route for the _Host.cshtml page to endpoint configuration in Startup.Configure:

    app.UseEndpoints(endpoints =>
    {
        ...
    
        endpoints.MapFallbackToPage("/_Host");
    });
    
  5. Add routable components to the app. For example:

    @page "/counter"
    
    <h1>Counter</h1>
    
    ...
    

For more information on namespaces, see the Component namespaces section.

Use routable components in an MVC app

This section pertains to adding components that are directly routable from user requests.

To support routable Razor components in MVC apps:

  1. Follow the guidance in the Configuration section.

  2. Add an App.razor file to the root of the project with the following content:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    

    Note

    With the release of ASP.NET Core 5.0.1 and for any additional 5.x releases, the Router component includes the PreferExactMatches parameter set to true. For more information, see Migrate from ASP.NET Core 3.1 to 5.0.

  3. Add a _Host.cshtml file to the Views/Home folder with the following content:

    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    Components use the shared _Layout.cshtml file for their layout.

    RenderMode configures whether the App component:

    • Is prerendered into the page.
    • Is rendered as static HTML on the page or if it includes the necessary information to bootstrap a Blazor app from the user agent.

    For more information on the Component Tag Helper, including passing parameters and RenderMode configuration, see Component Tag Helper in ASP.NET Core.

  4. Add an action to the Home controller:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. Add a low-priority route for the controller action that returns the _Host.cshtml view to the endpoint configuration in Startup.Configure:

    app.UseEndpoints(endpoints =>
    {
        ...
    
        endpoints.MapFallbackToController("Blazor", "Home");
    });
    
  6. Create a Pages folder and add routable components to the app. For example:

    @page "/counter"
    
    <h1>Counter</h1>
    
    ...
    

For more information on namespaces, see the Component namespaces section.

Render components from a page or view

This section pertains to adding components to pages or views, where the components aren't directly routable from user requests.

To render a component from a page or view, use the Component Tag Helper.

Render stateful interactive components

Stateful interactive components can be added to a Razor page or view.

When the page or view renders:

  • The component is prerendered with the page or view.
  • The initial component state used for prerendering is lost.
  • New component state is created when the SignalR connection is established.

The following Razor page renders a Counter component:

<h1>My Razor Page</h1>

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

For more information, see Component Tag Helper in ASP.NET Core.

Render noninteractive components

In the following Razor page, the Counter component is statically rendered with an initial value that's specified using a form. Since the component is statically rendered, the component isn't interactive:

<h1>My Razor Page</h1>

<form>
    <input type="number" asp-for="InitialValue" />
    <button type="submit">Set initial value</button>
</form>

<component type="typeof(Counter)" render-mode="Static" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

For more information, see Component Tag Helper in ASP.NET Core.

Component namespaces

When using a custom folder to hold the app's components, add the namespace representing the folder to either the page/view or to the _ViewImports.cshtml file. In the following example:

  • Change MyAppNamespace to the app's namespace.
  • If a folder named Components isn't used to hold the components, change Components to the folder where the components reside.
@using MyAppNamespace.Components

The _ViewImports.cshtml file is located in the Pages folder of a Razor Pages app or the Views folder of an MVC app.

For more information, see Create and use ASP.NET Core Razor components.