Integrate ASP.NET Core Razor components into ASP.NET Core apps

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 integration scenarios for ASP.NET Core apps.

Razor component integration

Razor components can be integrated into Razor Pages, MVC, and other types of ASP.NET Core apps. Razor components can also be integrated into any web app, including apps not based on ASP.NET Core, as custom HTML elements.

Use the guidance in the following sections depending on the app's requirements:

Use non-routable components in pages or views

Use the following guidance to integrate Razor components into pages or views of an existing Razor Pages or MVC app with the Component Tag Helper.

Note

If your app requires directly-routable components (not embedded into pages or views), skip this section and use the guidance in the Add Blazor support to an ASP.NET Core app section.

When server prerendering is used and 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.

For more information on rendering modes, including non-interactive static component rendering, see Component Tag Helper in ASP.NET Core. To save the state of prerendered Razor components, see Persist Component State Tag Helper in ASP.NET Core.

Add a Components folder to the root folder of the project.

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

Components/_Imports.razor:

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using {APP NAMESPACE}
@using {APP NAMESPACE}.Components

In the project's layout file (Pages/Shared/_Layout.cshtml in Razor Pages apps or Views/Shared/_Layout.cshtml in MVC apps):

  • Add the following <base> tag and Component Tag Helper for a HeadOutlet component to the <head> markup:

    <base href="~/" />
    <component type="typeof(Microsoft.AspNetCore.Components.Web.HeadOutlet)" 
        render-mode="ServerPrerendered" />
    

    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 HeadOutlet component is used to render head (<head>) content for page titles (PageTitle component) and other head elements (HeadContent component) set by Razor components. For more information, see Control head content in ASP.NET Core Blazor apps.

  • Add a <script> tag for the blazor.web.js script immediately before the Scripts render section (@await RenderSectionAsync(...)):

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

    The Blazor framework automatically adds the blazor.web.js script to the app.

Note

Typically, the layout loads via a _ViewStart.cshtml file.

Add an non-operational (no-op) App component to the project.

Components/App.razor:

@* No-op App component *@

Where services are registered, add services for Razor components and services to support rendering Interactive Server components.

At the top of the Program file, add a using statement to the top of the file for the project's components:

using {APP NAMESPACE}.Components;

In the preceding line, change the {APP NAMESPACE} placeholder to the app's namespace. For example:

using BlazorSample.Components;

In the Program file before the line that builds the app (builder.Build()):

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

For more information on adding support for Interactive Server and WebAssembly components, see ASP.NET Core Blazor render modes.

In the Program file immediately after the call to map Razor Pages (MapRazorPages) in a Razor Pages app or to map the default controller route (MapControllerRoute) in an MVC app, call MapRazorComponents to discover available components and specify the app's root component (the first component loaded). By default, the app's root component is the App component (App.razor). Chain a call to AddInteractiveServerRenderMode to configure interactive server-side rendering (interactive SSR) for the app:

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

Note

If the app hasn't already been updated to include Antiforgery Middleware, add the following line after UseAuthorization is called:

app.UseAntiforgery();

Integrate components into any page or view. For example, add an EmbeddedCounter component to the project's Components folder.

Components/EmbeddedCounter.razor:

<h1>Embedded 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 EmbeddedCounter component's namespace and embed the component into the page. When the Index page loads, the EmbeddedCounter 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}.Components
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

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

MVC:

In the project's Index view of an MVC app, add the EmbeddedCounter component's namespace and embed the component into the view. When the Index view loads, the EmbeddedCounter 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}.Components
@{
    ViewData["Title"] = "Home Page";
}

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

Add Blazor support to an ASP.NET Core app

This section covers adding Blazor support to an ASP.NET Core app:

Note

For the examples in this section, the example app's name and namespace is BlazorSample.

Add static server-side rendering (static SSR)

Add a Components folder to the app.

Add the following _Imports file for namespaces used by Razor components.

Components/_Imports.razor:

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using {APP NAMESPACE}
@using {APP NAMESPACE}.Components

Change the namespace placeholder ({APP NAMESPACE}) to the namespace of the app. For example:

@using BlazorSample
@using BlazorSample.Components

Add the Blazor router (<Router>, Router) to the app in a Routes component, which is placed in the app's Components folder.

Components/Routes.razor:

<Router AppAssembly="typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="routeData" />
        <FocusOnNavigate RouteData="routeData" Selector="h1" />
    </Found>
</Router>

Add an App component to the app, which serves as the root component, which is the first component the app loads.

Components/App.razor:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="@Assets["{ASSEMBLY NAME}.styles.css"]" />
    <HeadOutlet />
</head>

<body>
    <Routes />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="{ASSEMBLY NAME}.styles.css" />
    <HeadOutlet />
</head>

<body>
    <Routes />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>

The {ASSEMBLY NAME} placeholder is the app's assembly name. For example, a project with an assembly name of ContosoApp uses the ContosoApp.styles.css stylesheet file name.

Add a Pages folder to the Components folder to hold routable Razor components.

Add the following Welcome component to demonstrate static SSR.

Components/Pages/Welcome.razor:

@page "/welcome"

<PageTitle>Welcome!</PageTitle>

<h1>Welcome to Blazor!</h1>

<p>@message</p>

@code {
    private string message = 
        "Hello from a Razor component and welcome to Blazor!";
}

In the ASP.NET Core project's Program file:

  • Add a using statement to the top of the file for the project's components:

    using {APP NAMESPACE}.Components;
    

    In the preceding line, change the {APP NAMESPACE} placeholder to the app's namespace. For example:

    using BlazorSample.Components;
    
  • Add Razor component services (AddRazorComponents), which also automatically adds antiforgery services (AddAntiforgery). Add the following line before the line that calls builder.Build()):

    builder.Services.AddRazorComponents();
    
  • Add Antiforgery Middleware to the request processing pipeline with UseAntiforgery. UseAntiforgery is called after the call to UseRouting. If there are calls to UseRouting and UseEndpoints, the call to UseAntiforgery must go between them. A call to UseAntiforgery must be placed after calls to UseAuthentication and UseAuthorization.

    app.UseAntiforgery();
    
  • Add MapRazorComponents to the app's request processing pipeline with the App component (App.razor) specified as the default root component (the first component loaded). Place the following code before the line that calls app.Run:

    app.MapRazorComponents<App>();
    

When the app is run, the Welcome component is accessed at the /welcome endpoint.

Enable interactive server-side rendering (interactive SSR)

Follow the guidance in the Add static server-side rendering (static SSR) section.

In the app's Program file, add a call to AddInteractiveServerComponents where Razor component services are added with AddRazorComponents:

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

Add a call to AddInteractiveServerRenderMode where Razor components are mapped with MapRazorComponents:

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

Add the following Counter component to the app that adopts interactive server-side rendering (interactive SSR).

Components/Pages/Counter.razor:

@page "/counter"
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

When the app is run, the Counter component is accessed at /counter.

Enable interactive automatic (Auto) or client-side rendering (CSR)

Follow the guidance in the Add static server-side rendering (static SSR) section.

Components using the Interactive Auto render mode initially use interactive SSR. The .NET runtime and app bundle are downloaded to the client in the background and cached so that they can be used on future visits. Components using the Interactive WebAssembly render mode only render interactively on the client after the Blazor bundle is downloaded and the Blazor runtime activates. Keep in mind that when using the Interactive Auto or Interactive WebAssembly render modes, component code downloaded to the client isn't private. For more information, see ASP.NET Core Blazor render modes.

After deciding which render mode to adopt:

Add a package reference for the Microsoft.AspNetCore.Components.WebAssembly.Server NuGet package to the app.

Note

For guidance on adding packages to .NET apps, see the articles under Install and manage packages at Package consumption workflow (NuGet documentation). Confirm correct package versions at NuGet.org.

Create a donor Blazor Web App to provide assets to the app. Follow the guidance in the Tooling for ASP.NET Core Blazor article, selecting support for the following template features when generating the Blazor Web App.

For the app's name, use the same name as the ASP.NET Core app, which results in matching app name markup in components and matching namespaces in code. Using the same name/namespace isn't strictly required, as namespaces can be adjusted after assets are moved from the donor app to the ASP.NET Core app. However, time is saved by matching the namespaces at the outset.

Visual Studio:

  • For Interactive render mode, select Auto (Server and WebAssembly).
  • Set the Interactivity location to Per page/component.
  • Deselect the checkbox for Include sample pages.

.NET CLI:

  • Use the -int Auto option.
  • Don't use the -ai|--all-interactive option.
  • Pass the -e|--empty option.

From the donor Blazor Web App, copy the entire .Client project into the solution folder of the ASP.NET Core app.

Important

Don't copy the .Client folder into the ASP.NET Core project's folder. The best approach for organizing .NET solutions is to place each project of the solution into its own folder inside of a top-level solution folder. If a solution folder above the ASP.NET Core project's folder doesn't exist, create one. Next, copy the .Client project's folder from the donor Blazor Web App into the solution folder. The final project folder structure should have the following layout:

  • BlazorSampleSolution (top-level solution folder)
    • BlazorSample (original ASP.NET Core project)
    • BlazorSample.Client (.Client project folder from the donor Blazor Web App)

For the ASP.NET Core solution file, you can leave it in the ASP.NET Core project's folder. Alternatively, you can move the solution file or create a new one in the top-level solution folder as long as the project references correctly point to the project files (.csproj) of the two projects in the solution folder.

If you named the donor Blazor Web App when you created the donor project the same as the ASP.NET Core app, the namespaces used by the donated assets match those in the ASP.NET Core app. You shouldn't need to take further steps to match namespaces. If you used a different namespace when creating the donor Blazor Web App project, you must adjust the namespaces across the donated assets to match if you intend to use the rest of this guidance exactly as presented. If the namespaces don't match, either adjust the namespaces before proceeding or adjust the namespaces as you follow the remaining guidance in this section.

Delete the donor Blazor Web App, as it has no further use in this process.

Add the .Client project to the solution:

  • Visual Studio: Right-click the solution in Solution Explorer and select Add > Existing Project. Navigate to the .Client folder and select the project file (.csproj).

  • .NET CLI: Use the dotnet sln add command to add the .Client project to the solution.

Add a project reference from the ASP.NET Core project to the client project:

  • Visual Studio: Right-click the ASP.NET Core project and select Add > Project Reference. Select the .Client project and select OK.

  • .NET CLI: From the ASP.NET Core project's folder, use the following command:

    dotnet add reference ../BlazorSample.Client/BlazorSample.Client.csproj
    

    The preceding command assumes the following:

    • The project file name is BlazorSample.Client.csproj.
    • The .Client project is in a BlazorSample.Client folder inside the solution folder. The .Client folder is side-by-side with the ASP.NET Core project's folder.

    For more information on the dotnet add reference command, see dotnet add reference (.NET documentation).

Make the following changes to the ASP.NET Core app's Program file:

  • Add Interactive WebAssembly component services with AddInteractiveWebAssemblyComponents where Razor component services are added with AddRazorComponents.

    For interactive Auto rendering:

    builder.Services.AddRazorComponents()
        .AddInteractiveServerComponents()
        .AddInteractiveWebAssemblyComponents();
    

    For only Interactive WebAssembly rendering:

    builder.Services.AddRazorComponents()
        .AddInteractiveWebAssemblyComponents();
    
  • Add the Interactive WebAssembly render mode (AddInteractiveWebAssemblyRenderMode) and additional assemblies for the .Client project where Razor components are mapped with MapRazorComponents.

    For interactive automatic (Auto) rendering:

    app.MapRazorComponents<App>()
        .AddInteractiveServerRenderMode()
        .AddInteractiveWebAssemblyRenderMode()
        .AddAdditionalAssemblies(typeof(BlazorSample.Client._Imports).Assembly);
    

    For only Interactive WebAssembly rendering:

    app.MapRazorComponents<App>()
        .AddInteractiveWebAssemblyRenderMode()
        .AddAdditionalAssemblies(typeof(BlazorSample.Client._Imports).Assembly);
    

    In the preceding examples, change BlazorSample.Client to match the .Client project's namespace.

Add a Pages folder to the .Client project.

If the ASP.NET Core project has an existing Counter component:

  • Move the component to the Pages folder of the .Client project.
  • Remove the @rendermode directive at the top of the component file.

If the ASP.NET Core app doesn't have a Counter component, add the following Counter component (Pages/Counter.razor) to the .Client project:

@page "/counter"
@rendermode InteractiveAuto

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

If the app is only adopting Interactive WebAssembly rendering, remove the @rendermode directive and value:

- @rendermode InteractiveAuto

Run the solution from the ASP.NET Core app project:

  • Visual Studio: Confirm that the ASP.NET Core project is selected in Solution Explorer when running the app.

  • .NET CLI: Run the project from the ASP.NET Core project's folder.

To load the Counter component, navigate to /counter.

Implement Blazor's layout and styles

Optionally, assign a default layout component using the RouteView.DefaultLayout parameter of the RouteView component.

In Routes.razor, the following example uses a MainLayout component as the default layout:

<RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />

For more information, see ASP.NET Core Blazor layouts.

Blazor project template layout and stylesheets are available from the dotnet/aspnetcore GitHub repository:

  • MainLayout.razor
  • MainLayout.razor.css
  • NavMenu.razor
  • NavMenu.razor.css

Note

Documentation links to .NET reference source usually load the repository's default branch, which represents the current development for the next release of .NET. To select a tag for a specific release, use the Switch branches or tags dropdown list. For more information, see How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205).

Depending on how you organize your layout files in the app, you might need to add an @using statement for the layout files' folder in the app's _Imports.razor file in order to surface them for use in the app's components.

There's no need to explicitly reference stylesheets when using CSS isolation. The Blazor framework automatically bundles individual component stylesheets. The app's bundled stylesheet is already referenced in the app's App component ({ASSEMBLY NAME}.styles.css, where the {ASSEMBLY NAME} placeholder is the app's assembly name).

Return a RazorComponentResult from an MVC controller action

An MVC controller action can return a component with RazorComponentResult<TComponent>.

Components/Welcome.razor:

<PageTitle>Welcome!</PageTitle>

<h1>Welcome!</h1>

<p>@Message</p>

@code {
    [Parameter]
    public string? Message { get; set; }
}

In a controller:

public IResult GetWelcomeComponent() => 
    new RazorComponentResult<Welcome>(new { Message = "Hello, world!" });

Only HTML markup for the rendered component is returned. Layouts and HTML page markup aren't automatically rendered with the component. To produce a complete HTML page, the app can maintain a Blazor layout that provides HTML markup for <html>, <head>, <body>, and other tags. The component includes the layout with the @layout Razor directive at the top of the component definition file, Welcome.razor for the example in this section. The following example assumes that the app has a layout named RazorComponentResultLayout (Components/Layout/RazorComponentResultLayout.razor):

@using BlazorSample.Components.Layout
@layout RazorComponentResultLayout

You can avoid placing the @using statement for the Layout folder in individual components by moving it to the app's _Imports.razor file.

For more information, see ASP.NET Core Blazor layouts.

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

For example:

@using BlazorSample.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 resources

Prerender ASP.NET Core Razor components