Prerender and integrate ASP.NET Core Razor components

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.

Solution configuration

Prerendering configuration

To set up prerendering for a hosted 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 WebAssembly project template with the hosted option:

    • Visual Studio: In the Additional information dialog, select the ASP.NET Core hosted checkbox when creating the Blazor WebAssembly app. In this article's examples, the solution is named BlazorHosted.
    • Visual Studio Code/.NET CLI command shell: dotnet new blazorwasm -ho (use the -ho|--hosted option). Use the -o|--output {LOCATION} option to create a folder for the solution and set the solution's project namespaces. In this article's examples, the solution is named BlazorHosted (dotnet new blazorwasm -ho -o BlazorHosted).

    For the examples in this article, the client project's namespace is BlazorHosted.Client, and the server project's namespace is BlazorHosted.Server.

  2. Delete the wwwroot/index.html file from the Blazor WebAssembly Client project.

  3. In the Client project, delete the following lines in Program.cs:

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  4. Add _Host.cshtml and _Layout.cshtml files to the Server project's Pages folder. You can obtain the files from a project created from the Blazor Server template using Visual Studio or using the .NET CLI with the dotnet new blazorserver -o BlazorServer command in a command shell (the -o BlazorServer option creates a folder for the project). After placing the files into the Server project's Pages folder:

    Make the following changes to the _Layout.cshtml file:

    • Update the Pages namespace at the top of the file to match the namespace of the Server app's pages. The {APP NAMESPACE} placeholder in the following example represents the namespace of the donor app's pages that provided the _Layout.cshtml file:

      Delete:

      - @namespace {APP NAMESPACE}.Pages
      

      Add:

      @namespace BlazorHosted.Server.Pages
      
    • Add an @using directive for the Client project at the top of the file:

      @using BlazorHosted.Client
      
    • Update the stylesheet links to point to the WebAssembly project's stylesheets. In the following example, the client project's namespace is BlazorHosted.Client. The {APP NAMESPACE} placeholder represents the namespace of the donor app that provided the _Layout.cshtml file. Update the Component Tag Helper (<component> tag) for the HeadOutlet component to prerender the component.

      Delete:

      - <link href="css/site.css" rel="stylesheet" />
      - <link href="{APP NAMESPACE}.styles.css" rel="stylesheet" />
      - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
      

      Add:

      <link href="css/app.css" rel="stylesheet" />
      <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
      <component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
      

      Note

      Leave the <link> element that requests the Bootstrap stylesheet (css/bootstrap/bootstrap.min.css) in place.

    • Update the Blazor script source to use the client-side Blazor WebAssembly script:

      Delete:

      - <script src="_framework/blazor.server.js"></script>
      

      Add:

      <script src="_framework/blazor.webassembly.js"></script>
      

    In the _Host.cshtml file:

    • Change the Pages namespace to that of the Client project. The {APP NAMESPACE} placeholder represents the namespace of the donor app's pages that provided the _Host.cshtml file:

      Delete:

      - @namespace {APP NAMESPACE}.Pages
      

      Add:

      @namespace BlazorHosted.Client
      
    • Update the render-mode of the Component Tag Helper to prerender the root App component with WebAssemblyPrerendered:

      Delete:

      - <component type="typeof(App)" render-mode="ServerPrerendered" />
      

      Add:

      <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
      
  5. In endpoint mapping of the Server project in Program.cs, change the fallback from the index.html file to the _Host.cshtml page:

    Delete:

    - app.MapFallbackToFile("index.html");
    

    Add:

    app.MapFallbackToPage("/_Host");
    
  6. Run the Server project. The hosted Blazor WebAssembly app is prerendered by the Server project for clients.

Configuration for embedding Razor components into pages and views

The following sections and examples for embedding Razor components from the Client Blazor WebAssembly app into pages and views of the server app require additional configuration.

The Server project must have the following files and folders.

Razor Pages:

  • Pages/Shared/_Layout.cshtml
  • Pages/_ViewImports.cshtml
  • Pages/_ViewStart.cshtml

MVC:

  • Views/Shared/_Layout.cshtml
  • Views/_ViewImports.cshtml
  • Views/_ViewStart.cshtml

The preceding files can be obtained by generating an app from the ASP.NET Core project templates using:

  • Visual Studio's new project creation tools.
  • Opening a command shell and executing dotnet new razor -o {APP NAME} (Razor Pages) or dotnet new mvc -o {APP NAME} (MVC). The option -o|--output with a value for the {APP NAME} placeholder provides a name for the app and creates a folder for the app.

Update the namespaces in the imported _ViewImports.cshtml file to match those in use by the Server project receiving the files.

Pages/_ViewImports.cshtml (Razor Pages):

@using BlazorHosted.Server
@namespace BlazorHosted.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Views/_ViewImports.cshtml (MVC):

@using BlazorHosted.Server
@using BlazorHosted.Server.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Update the imported layout file (_Layout.cshtml) to include the Client project's styles. In the following example, the Client project's namespace is BlazorHosted.Client. The <title> element can be updated at the same time. The {APP NAME} placeholder represents the donor project's app name.

Pages/Shared/_Layout.cshtml (Razor Pages) or Views/Shared/_Layout.cshtml (MVC):

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-   <title>@ViewData["Title"] - {APP NAME}</title>
+   <title>@ViewData["Title"] - BlazorHosted</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
+   <link href="css/app.css" rel="stylesheet" />
+   <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
</head>

The imported layout contains Home and Privacy navigation links. To make the Home link point to the hosted Blazor WebAssembly app, change the hyperlink:

- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

In an MVC layout file:

- <a class="nav-link text-dark" asp-area="" asp-controller="Home" 
-     asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

To make the Privacy link lead to a privacy page (Razor Pages), add a privacy page to the Server project.

Pages/Privacy.cshtml in the Server project:

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

For an MVC-based privacy view, create a privacy view in the Server project.

View/Home/Privacy.cshtml in the Server project:

@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

In the Home controller of the MVC app, return the view.

Add the following code to Controllers/HomeController.cs:

public IActionResult Privacy()
{
    return View();
}

If you import files from a donor app, be sure to update any namespaces in the files to match that of the Server project (for example, BlazorHosted.Server).

Import static assets to the Server project from the donor project's wwwroot folder:

  • wwwroot/css folder and contents
  • wwwroot/js folder and contents
  • wwwroot/lib folder and contents

If the donor project is created from an ASP.NET Core project template and the files aren't modified, you can copy the entire wwwroot folder from the donor project into the Server project and remove the favicon.ico icon file.

Warning

Avoid placing the same file (for example, favicon.ico) into both the Client and Server wwwroot folders. If the same file is present in both folders an exception is thrown because the static asset in each folder shares the same web root path:

The static web asset '...\favicon.ico' has a conflicting web root path '/wwwroot/favicon.ico' with the project file 'wwwroot\favicon.ico'.

Therefore, host a static asset in either wwwroot folder, not both.

After adopting the preceding configuration, embed Razor components into pages or views of the Server project. Use the guidance in the following sections of this article:

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

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

After configuring the solution, including the additional configuration, the Component Tag Helper supports two render modes for rendering a component from a Blazor WebAssembly app in a page or view:

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 project's Pages namespace. In the following example, the Client project's namespace is BlazorHosted.Client.

In the Server project, Pages/RazorPagesCounter1.cshtml:

@page
@using BlazorHosted.Client.Pages

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

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

Run the Server project. Navigate to the Razor page at /razorpagescounter1. The prerendered Counter component is embedded in the page.

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.

Additional work might be required depending on the static resources that components use and how layout pages are organized in an app. Typically, scripts are added to a page or view's Scripts render section and stylesheets are added to the layout's <head> element content.

Render components in a page or view with a CSS selector

After configuring the solution, including the additional configuration, add root components to the Client project of a hosted Blazor WebAssembly solution in the Program.cs file. 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 counter-component. In the following example, the Client project's namespace is BlazorHosted.Client.

In Program.cs file of the Client project, add the namespace for the project's Razor components to the top of the file:

using BlazorHosted.Client.Pages;

After the builder is established in Program.cs, add the Counter component as a root component:

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

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.

In the Server project, Pages/RazorPagesCounter2.cshtml:

@page

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

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

Run the Server project. Navigate to the Razor page at /razorpagescounter2. The prerendered Counter component is embedded in the page.

Additional work might be required depending on the static resources that components use and how layout pages are organized in an app. Typically, scripts are added to a page or view's Scripts render section and stylesheets are added to the layout's <head> element content.

Note

The preceding example throws a JSException if a Blazor WebAssembly app is prerendered and integrated into a Razor Pages or MVC app simultaneously with the use of a CSS selector. Navigating to one of the Client project's Razor components or navigating to a page or view of the Server with an embedded component throws one or more JSException.

This is normal behavior because prerendering and integrating a Blazor WebAssembly app with routable Razor components is incompatible with the use of CSS selectors.

If you've been working with the examples in the preceding sections and just wish to see the CSS selector work in your sample app, comment out the specification of the App root component of the Client project's Program.cs file:

- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");

Navigate to the page or view with the embedded Razor component that uses a CSS selector (for example, /razorpagescounter2 of the preceding example). The page or view loads with the embedded component, and the embedded component functions as expected.

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 project, use the guidance in the following sections depending on the project's requirements:

Configuration

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

  1. In the project's layout file:

    • Add the following <base> tag to the <head> element in Pages/Shared/_Layout.cshtml (Razor Pages) or Views/Shared/_Layout.cshtml (MVC):

      <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.

    • Add a <script> tag for the blazor.server.js script immediately before the Scripts render section (@await RenderSectionAsync(...)) in the app's layout.

      Pages/Shared/_Layout.cshtml (Razor Pages) or Views/Shared/_Layout.cshtml (MVC):

      <script src="_framework/blazor.server.js"></script>
      

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

  2. Add an imports file to the root folder of the project with the following content. Change the {APP NAMESPACE} placeholder to the namespace of the project.

    _Imports.razor:

    @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.AspNetCore.Components.Web.Virtualization
    @using Microsoft.JSInterop
    @using {APP NAMESPACE}
    
  3. Register the Blazor Server services in Program.cs where services are registered:

    builder.Services.AddServerSideBlazor();
    
  4. Add the Blazor Hub endpoint to the endpoints of Program.cs where routes are mapped.

    Place the following line after the call to MapRazorPages (Razor Pages) or MapControllerRoute (MVC):

    app.MapBlazorHub();
    
  5. Integrate components into any page or view. For example, add a Counter component to the project's Shared folder.

    Pages/Shared/Counter.razor (Razor Pages) or Views/Shared/Counter.razor (MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor Pages:

    In the project's Index page of a Razor Pages app, add the Counter component's namespace and embed the component into the page. When the Index page loads, the Counter component is prerendered in the page. In the following example, replace the {APP NAMESPACE} placeholder with the project's namespace.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

    MVC:

    In the project's Index view of an MVC app, add the Counter component's namespace and embed the component into the view. When the Index view loads, the Counter component is prerendered in the page. In the following example, replace the {APP NAMESPACE} placeholder with the project's namespace.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

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 component to the project root with the following content.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="@routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. Add a _Host page to the project with the following content.

    Pages/_Host.cshtml:

    @page "/blazor"
    @namespace {APP NAMESPACE}.Pages.Shared
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @{
        Layout = "_Layout";
    }
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    In this scenario, 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. In the Program.cs endpoints, add a low-priority route for the _Host page as the last endpoint:

    app.MapFallbackToPage("/_Host");
    
  5. Add routable components to the project. The following example is a RoutableCounter component based on the Counter component in the Blazor project templates.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. Run the project and navigate to the routable RoutableCounter component at /routable-counter.

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 component to the project root with the following content.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="@routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. Add a _Host view to the project with the following content.

    Views/Home/_Host.cshtml:

    @namespace {APP NAMESPACE}.Views.Shared
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @{
        Layout = "_Layout";
    }
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    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.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. In the Program.cs endpoints, add a low-priority route for the controller action that returns the _Host view:

    app.MapFallbackToController("Blazor", "Home");
    
  6. Create a Pages folder in the MVC app and add routable components. The following example is a RoutableCounter component based on the Counter component in the Blazor project templates.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. Run the project and navigate to the routable RoutableCounter component at /routable-counter.

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 project's Razor components, add the namespace representing the folder to either the page/view or to the _ViewImports.cshtml file. In the following example:

  • Components are stored in the Components folder of the project.
  • The {APP NAMESPACE} placeholder is the project's namespace. Components represents the name of the folder.
@using {APP NAMESPACE}.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 ASP.NET Core Razor components.

Preserve prerendered state

Without preserving prerendered state, any state that used during prerendering is lost and must be recreated when the app is fully loaded. If any state is setup asynchronously, the UI may flicker as the prerendered UI is replaced with temporary placeholders and then fully rendered again.

To solve these problems, Blazor supports persisting state in a prerendered page using the Preserve Component State Tag Helper (<preserve-component-state />). Add the <preserve-component-state /> tag inside the closing </body> tag of _Layout.cshtml.

Pages/_Layout.cshtml:

<body>
    ...

    <persist-component-state />
</body>

Pages/_Layout.cshtml:

<body>
    ...

    <persist-component-state />
</body>

In the app, decide what state to persist using the ComponentApplicationState service. The ComponentApplicationState.OnPersisting event is fired just before the state is persisted into the prerendered page, which allows a component to retrieve the state when initializing the component.

The following example shows how the weather forecast in the FetchData component from an app based on the Blazor project template is persisted during prerendering and then retrieved to initialize the component. The Persist Component State Tag Helper persists the component state after all component invocations.

Pages/FetchData.razor:

@page "/fetchdata"
@implements IDisposable
@inject ComponentApplicationState ApplicationState

...

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        ApplicationState.OnPersisting += PersistForecasts;

        if (!ApplicationState
            .TryTakeAsJson<WeatherForecast[]>("fetchdata", out forecasts))
        {
            forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
        }
    }

    private Task PersistForecasts()
    {
        ApplicationState.PersistAsJson("fetchdata", forecasts);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        ApplicationState.OnPersisting -= PersistForecasts;
    }
}

By initializing components with the same state used during prerendering, any expensive initialization steps are only executed once. The rendered UI also matches the prerendered UI, so no flicker occurs in the browser.

Additional Blazor WebAssembly resources

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.

Solution configuration

Prerendering configuration

To set up prerendering for a hosted 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 WebAssembly project template with the hosted option:

    • Visual Studio: In the Additional information dialog, select the ASP.NET Core hosted checkbox when creating the Blazor WebAssembly app. In this article's examples, the solution is named BlazorHosted.
    • Visual Studio Code/.NET CLI command shell: dotnet new blazorwasm -ho (use the -ho|--hosted option). Use the -o|--output {LOCATION} option to create a folder for the solution and set the solution's project namespaces. In this article's examples, the solution is named BlazorHosted (dotnet new blazorwasm -ho -o BlazorHosted).

    For the examples in this article, the client project's namespace is BlazorHosted.Client, and the server project's namespace is BlazorHosted.Server.

  2. Delete the wwwroot/index.html file from the Blazor WebAssembly Client project.

  3. In the Client project, delete the following line in Program.cs:

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

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

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

      - <link href="css/site.css" rel="stylesheet" />
      - <link href="_content/BlazorServer/_framework/scoped.styles.css" rel="stylesheet" />
      + <link href="css/app.css" rel="stylesheet" />
      + <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
      

      Note

      Leave the <link> element that requests the Bootstrap stylesheet (css/bootstrap/bootstrap.min.css) in place.

    • Update the render-mode of the Component Tag Helper to prerender the root App component with WebAssemblyPrerendered:

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

      - <script src="_framework/blazor.server.js"></script>
      + <script src="_framework/blazor.webassembly.js"></script>
      
  5. In Startup.Configure of the Server project, change the fallback from the index.html file to the _Host.cshtml page.

    Startup.cs:

    - endpoints.MapFallbackToFile("index.html");
    + endpoints.MapFallbackToPage("/_Host");
    
  6. Run the Server project. The hosted Blazor WebAssembly app is prerendered by the Server project for clients.

Configuration for embedding Razor components into pages and views

The following sections and examples in this article for embedding Razor components of the client Blazor WebAssembly app into pages and views of the server app require additional configuration.

Use a default Razor Pages or MVC layout file in the Server project. The Server project must have the following files and folders.

Razor Pages:

  • Pages/Shared/_Layout.cshtml
  • Pages/_ViewImports.cshtml
  • Pages/_ViewStart.cshtml

MVC:

  • Views/Shared/_Layout.cshtml
  • Views/_ViewImports.cshtml
  • Views/_ViewStart.cshtml

Obtain the preceding files from an app created from the Razor Pages or MVC project template. For more information, see Tutorial: Get started with Razor Pages in ASP.NET Core or Get started with ASP.NET Core MVC.

Update the namespaces in the imported _ViewImports.cshtml file to match those in use by the Server project receiving the files.

Update the imported layout file (_Layout.cshtml) to include the Client project's styles. In the following example, the Client project's namespace is BlazorHosted.Client. The <title> element can be updated at the same time.

Pages/Shared/_Layout.cshtml (Razor Pages) or Views/Shared/_Layout.cshtml (MVC):

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-   <title>@ViewData["Title"] - DonorProject</title>
+   <title>@ViewData["Title"] - BlazorHosted</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
+   <link href="css/app.css" rel="stylesheet" />
+   <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
</head>

The imported layout contains Home and Privacy navigation links. To make the Home link point to the hosted Blazor WebAssembly app, change the hyperlink:

- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

In an MVC layout file:

- <a class="nav-link text-dark" asp-area="" asp-controller="Home" 
-     asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

To make the Privacy link lead to a privacy page, add a privacy page to the Server project.

Pages/Privacy.cshtml in the Server project:

@page
@model BlazorHosted.Server.Pages.PrivacyModel
@{
}

<h1>Privacy Policy</h1>

If an MVC-based privacy view is preferred, create a privacy view in the Server project.

View/Home/Privacy.cshtml:

@{
    ViewData["Title"] = "Privacy Policy";
}

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

In the Home controller, return the view.

Controllers/HomeController.cs:

+ public IActionResult Privacy()
+ {
+     return View();
+ }

Import static assets to the Server project from the donor project's wwwroot folder:

  • wwwroot/css folder and contents
  • wwwroot/js folder and contents
  • wwwroot/lib folder and contents

If the donor project is created from an ASP.NET Core project template and the files aren't modified, you can copy the entire wwwroot folder from the donor project into the Server project and remove the favicon.ico icon file.

Note

If the Client and Server projects contain the same static asset in their wwwroot folders (for example, favicon.ico), an exception is thrown because the static asset in each folder shares the same web root path:

The static web asset '...\favicon.ico' has a conflicting web root path '/wwwroot/favicon.ico' with the project file 'wwwroot\favicon.ico'.

Therefore, host a static asset in either wwwroot folder, not both.

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

After configuring the solution, including the additional configuration, the Component Tag Helper supports two render modes for rendering a component from a Blazor WebAssembly app in a page or view:

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 project's Pages namespace. In the following example, the Client project's namespace is BlazorHosted.Client.

In the Server project, Pages/RazorPagesCounter1.cshtml:

@page
@using BlazorHosted.Client.Pages

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

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

Run the Server project. Navigate to the Razor page at /razorpagescounter1. The prerendered Counter component is embedded in the page.

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.

Additional work might be required depending on the static resources that components use and how layout pages are organized in an app. Typically, scripts are added to a page or view's Scripts render section and stylesheets are added to the layout's <head> element content.

Render components in a page or view with a CSS selector

After configuring the solution, including the additional configuration, add root components to the Client project of a hosted Blazor WebAssembly solution in 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 counter-component. In the following example, the Client project's namespace is BlazorHosted.Client.

In Program.cs of the Client project, add the namespace for the project's Razor components to the top of the file:

+ using BlazorHosted.Client.Pages;

After the builder is established in Program.cs, add the Counter component as a root component:

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

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.

In the Server project, Pages/RazorPagesCounter2.cshtml:

@page

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

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

Run the Server project. Navigate to the Razor page at /razorpagescounter2. The prerendered Counter component is embedded in the page.

Additional work might be required depending on the static resources that components use and how layout pages are organized in an app. Typically, scripts are added to a page or view's Scripts render section and stylesheets are added to the layout's <head> element content.

Note

The preceding example throws a JSException if a Blazor WebAssembly app is prerendered and integrated into a Razor Pages or MVC app simultaneously with a CSS selector. Navigating to one of the Client project's Razor components throws the following exception:

Microsoft.JSInterop.JSException: Could not find any element matching selector '#counter-component'.

This is normal behavior because prerendering and integrating a Blazor WebAssembly app with routable Razor components is incompatible with the use of CSS selectors.

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 project, use the guidance in the following sections depending on the project's requirements:

Configuration

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

  1. In the project's layout file:

    • Add the following <base> tag to the <head> element in Pages/Shared/_Layout.cshtml (Razor Pages) or Views/Shared/_Layout.cshtml (MVC):

      + <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.

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

      Pages/Shared/_Layout.cshtml (Razor Pages) or Views/Shared/_Layout.cshtml (MVC):

          ...
      +   <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 a blazor.server.js script file to the app.

  2. Add an imports file to the root folder of the project with the following content. Change the {APP NAMESPACE} placeholder to the namespace of the project.

    _Imports.razor:

    @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 {APP NAMESPACE}
    
  3. Register the Blazor Server service in Startup.ConfigureServices.

    Startup.cs:

    + services.AddServerSideBlazor();
    
  4. Add the Blazor Hub endpoint to the endpoints (app.UseEndpoints) of Startup.Configure.

    Startup.cs:

    + endpoints.MapBlazorHub();
    
  5. Integrate components into any page or view. For example, add a Counter component to the project's Shared folder.

    Pages/Shared/Counter.razor (Razor Pages) or Views/Shared/Counter.razor (MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor Pages:

    In the project's Index page of a Razor Pages app, add the Counter component's namespace and embed the component into the page. When the Index page loads, the Counter component is prerendered in the page. In the following example, replace the {APP NAMESPACE} placeholder with the project's namespace.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

    In the preceding example, replace the {APP NAMESPACE} placeholder with the app's namespace.

    MVC:

    In the project's Index view of an MVC app, add the Counter component's namespace and embed the component into the view. When the Index view loads, the Counter component is prerendered in the page. In the following example, replace the {APP NAMESPACE} placeholder with the project's namespace.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

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 component to the project root with the following content.

    App.razor:

    @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 page to the project with the following content.

    Pages/_Host.cshtml:

    @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. In the Startup.Configure endpoints of Startup.cs, add a low-priority route for the _Host page as the last endpoint:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
    +   endpoints.MapFallbackToPage("/_Host");
    });
    
  5. Add routable components to the project.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. Run the project and navigate to the routable RoutableCounter component at /routable-counter.

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 component to the project root with the following content.

    App.razor:

    @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 view to the project with the following content.

    Views/Home/_Host.cshtml:

    @{
        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.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. In the Startup.Configure endpoints of Startup.cs, add a low-priority route for the controller action that returns the _Host view:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapBlazorHub();
    +   endpoints.MapFallbackToController("Blazor", "Home");
    });
    
  6. Add routable components to the project.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. Run the project and navigate to the routable RoutableCounter component at /routable-counter.

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 project's Razor components, add the namespace representing the folder to either the page/view or to the _ViewImports.cshtml file. In the following example:

  • Components are stored in the Components folder of the project.
  • The {APP NAMESPACE} placeholder is the project's namespace. Components represents the name of the folder.
@using {APP NAMESPACE}.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 ASP.NET Core Razor components.

Additional Blazor WebAssembly resources

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 project, use the guidance in the following sections depending on the project's requirements:

Configuration

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

  1. In the project's layout file:

    • Add the following <base> tag to the <head> element in Pages/Shared/_Layout.cshtml (Razor Pages) or Views/Shared/_Layout.cshtml (MVC):

      + <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.

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

      Pages/Shared/_Layout.cshtml (Razor Pages) or Views/Shared/_Layout.cshtml (MVC):

          ...
      +   <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 a blazor.server.js script file to the app.

  2. Add an imports file to the root folder of the project with the following content. Change the {APP NAMESPACE} placeholder to the namespace of the project.

    _Imports.razor:

    @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 {APP NAMESPACE}
    
  3. Register the Blazor Server service in Startup.ConfigureServices.

    Startup.cs:

    + services.AddServerSideBlazor();
    
  4. Add the Blazor Hub endpoint to the endpoints (app.UseEndpoints) of Startup.Configure.

    Startup.cs:

    + endpoints.MapBlazorHub();
    
  5. Integrate components into any page or view. For example, add a Counter component to the project's Shared folder.

    Pages/Shared/Counter.razor (Razor Pages) or Views/Shared/Counter.razor (MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor Pages:

    In the project's Index page of a Razor Pages app, add the Counter component's namespace and embed the component into the page. When the Index page loads, the Counter component is prerendered in the page. In the following example, replace the {APP NAMESPACE} placeholder with the project's namespace.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

    In the preceding example, replace the {APP NAMESPACE} placeholder with the app's namespace.

    MVC:

    In the project's Index view of an MVC app, add the Counter component's namespace and embed the component into the view. When the Index view loads, the Counter component is prerendered in the page. In the following example, replace the {APP NAMESPACE} placeholder with the project's namespace.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

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 component to the project root with the following content.

    App.razor:

    @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>
    
  3. Add a _Host page to the project with the following content.

    Pages/_Host.cshtml:

    @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. In the Startup.Configure endpoints of Startup.cs, add a low-priority route for the _Host page as the last endpoint:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
    +   endpoints.MapFallbackToPage("/_Host");
    });
    
  5. Add routable components to the project.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. Run the project and navigate to the routable RoutableCounter component at /routable-counter.

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 component to the project root with the following content.

    App.razor:

    @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>
    
  3. Add a _Host view to the project with the following content.

    Views/Home/_Host.cshtml:

    @{
        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.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. In the Startup.Configure endpoints of Startup.cs, add a low-priority route for the controller action that returns the _Host view:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapBlazorHub();
    +   endpoints.MapFallbackToController("Blazor", "Home");
    });
    
  6. Add routable components to the project.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. Run the project and navigate to the routable RoutableCounter component at /routable-counter.

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 project's Razor components, add the namespace representing the folder to either the page/view or to the _ViewImports.cshtml file. In the following example:

  • Components are stored in the Components folder of the project.
  • The {APP NAMESPACE} placeholder is the project's namespace. Components represents the name of the folder.
@using {APP NAMESPACE}.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 ASP.NET Core Razor components.

Additional Blazor Server resources