将 ASP.NET Core Razor 组件集成到 ASP.NET Core 应用

本文介绍 ASP.NET Core 应用的 Razor 组件集成方案。

Razor 组件集成

Razor 组件可以集成到 Razor 页面、MVC 和其他类型的 ASP.NET Core 应用中。 Razor 组件还可以作为自定义 HTML 元素集成到任何 Web 应用,包括不是基于 ASP.NET Core 的应用。

根据应用的要求,使用以下部分中的指南:

在页面或视图中使用不可路由的组件

使用以下指南通过组件标签帮助程序将 Razor 组件集成到现有的 Razor 页面或 MVC 应用的页面和视图中。

注意

如果应用需要直接路由的组件(未嵌入到页面或视图中),请跳过本部分,并使用将 Blazor 支持添加到 ASP.NET 核心应用部分中的指南。

使用服务器预呈现并且页面或视图呈现时:

  • 该组件通过页面或视图预呈现。
  • 用于预呈现的初始组件状态丢失。
  • 建立 SignalR 连接时,将创建新的组件状态。

有关呈现模式(包括非交互式静态组件呈现)的详细信息,请参阅 ASP.NET Core 中的组件标签帮助程序。 要保存预呈现的 Razor 组件的状态,请参阅 ASP.NET Core 中的持久组件状态标签帮助程序

Components 文件夹添加到项目的根文件夹。

将具有以下内容的导入文件添加到 Components 文件夹。 将 {APP NAMESPACE} 占位符更改为项目的命名空间。

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

在项目的布局文件(Razor Pages 应用中的 Pages/Shared/_Layout.cshtml 或 MVC 应用中的 Views/Shared/_Layout.cshtml)中:

  • HeadOutlet 组件的以下 <base> 标签和组件标签帮助程序添加到 <head> 标记:

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

    前面示例中的 href 值(应用基路径)假设应用驻留在根 URL 路径 (/) 处。 如果应用是子应用程序,请按照托管和部署 ASP.NET Core Blazor 一文的“应用基路径”部分中的指导进行操作。

    HeadOutlet 组件用于呈现页面标题(PageTitle 组件)的头 (<head>) 内容和由 Razor 组件设置的其他头元素(HeadContent 组件)。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制头内容

  • 在紧接着 Scripts 呈现部分 (@await RenderSectionAsync(...)) 的前方为 blazor.web.js 脚本添加 <script> 标记:

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

    Blazor 框架会自动将 blazor.web.js 脚本添加到应用。

注意

通常,布局通过 _ViewStart.cshtml 文件加载。

将非操作(无操作)App 组件添加到项目。

Components/App.razor

@* No-op App component *@

注册服务时,为 Razor 组件和服务添加服务以支持呈现交互式服务器组件。

Program 文件顶部,将 using 语句添加到项目组件的文件顶部:

using {APP NAMESPACE}.Components;

在上面的行中,将 {APP NAMESPACE} 占位符更改为应用的命名空间。 例如:

using BlazorSample.Components;

Program 文件中生成应用的行之前 (builder.Build()):

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

有关添加对交互式服务器和 WebAssembly 组件的支持的详细信息,请参阅 ASP.NET Core Blazor 呈现模式

在 Razor Pages 应用中调用映射 Razor Pages (MapRazorPages) 或在 MVC 应用中映射默认控制器路由 (MapControllerRoute) 后,立即在 Program 文件中调用 MapRazorComponents,以发现可用组件并指定应用的根组件(即加载的第一个组件)。 默认情况下,应用的根组件是 App 组件 (App.razor)。 链接对 AddInteractiveServerRenderMode 的调用,为应用配置交互式服务器端呈现(交互式 SSR):

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

注意

如果应用尚未更新以包含 Antiforgery 中间件,请在调用 UseAuthorization 后添加以下行:

app.UseAntiforgery();

将组件集成到任何页面或视图。 例如,将 EmbeddedCounter 组件添加到项目的 Components 文件夹。

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:

在 Razor Pages 应用的项目 Index 页中,添加 EmbeddedCounter 组件的命名空间,并将组件嵌入到页面中。 加载 Index 页面时,将在页面中预呈现 EmbeddedCounter 组件。 在下面的示例中,将 {APP NAMESPACE} 占位符替换为项目的命名空间。

Pages/Index.cshtml

@page
@using {APP NAMESPACE}.Components
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

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

MVC:

在 MVC 应用的项目 Index 视图中,添加 EmbeddedCounter 组件的命名空间,并将组件嵌入到视图中。 加载 Index 视图时,将在页面中预呈现 EmbeddedCounter 组件。 在下面的示例中,将 {APP NAMESPACE} 占位符替换为项目的命名空间。

Views/Home/Index.cshtml

@using {APP NAMESPACE}.Components
@{
    ViewData["Title"] = "Home Page";
}

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

将 Blazor 支持添加到 ASP.NET Core 应用

本部分介绍如何将 Blazor 支持添加到 ASP.NET Core 应用:

注意

对于本部分中的示例,示例应用的名称和命名空间为 BlazorSample

添加静态服务器端呈现(静态 SSR)

Components 文件夹添加到应用。

为 Razor 组件使用的命名空间添加以下 _Imports 文件。

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

将命名空间占位符 ({APP NAMESPACE}) 更改为应用的命名空间。 例如:

@using BlazorSample
@using BlazorSample.Components

将 Blazor 路由器(<Router>Router)添加到 Routes 组件中的应用,该组件放置在应用的 Components 文件夹中。

Components/Routes.razor

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

App 组件添加到应用,该组件充当根组件(即,应用加载的第一个组件)。

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>

{ASSEMBLY NAME} 占位符是应用的程序集名称。 例如,程序集名称为 ContosoApp 的项目使用 ContosoApp.styles.css 样式表文件名。

Pages 文件夹添加到 Components 文件夹以保存可路由的 Razor 组件。

添加以下 Welcome 组件来演示静态 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!";
}

在 ASP.NET Core 项目的 Program 文件中:

  • using 语句添加到项目组件的文件顶部:

    using {APP NAMESPACE}.Components;
    

    在上面的行中,将 {APP NAMESPACE} 占位符更改为应用的命名空间。 例如:

    using BlazorSample.Components;
    
  • 添加 Razor 组件服务 (AddRazorComponents),同时也会自动添加防伪服务 (AddAntiforgery)。 在调用 builder.Build() 的行之前添加以下行:

    builder.Services.AddRazorComponents();
    
  • 使用 UseAntiforgeryAntiforgery 中间件添加到请求处理管道。 UseAntiforgery 在调用 UseRouting 之后调用。 如果有对 UseRoutingUseEndpoints 的调用,则对 UseAntiforgery 的调用必须介于两者之间。 对 UseAntiforgery 的调用必须在对 UseAuthenticationUseAuthorization 的调用后发出。

    app.UseAntiforgery();
    
  • 使用指定为默认根组件(即加载的第一个组件)的 App 组件 (App.razor) 将 MapRazorComponents 添加到应用的请求处理管道。 将以下代码置于调用 app.Run 的行前面:

    app.MapRazorComponents<App>();
    

运行应用时,将在 /welcome 终结点处访问 Welcome 组件。

启用交互式服务器端呈现(交互式 SSR)

按照添加静态服务器端呈现(静态 SSR)部分中的指导进行操作。

在应用的 Program 文件中,添加对 AddInteractiveServerComponents 的调用,其中使用 AddRazorComponents 添加了 Razor 组件服务:

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

添加对 AddInteractiveServerRenderMode 的调用,其中 Razor 组件是使用 MapRazorComponents 映射的:

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

将以下 Counter 组件添加到采用交互式服务器端呈现(交互式 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++;
    }
}

运行应用时,在 /counter 访问 Counter 组件。

启用交互式自动 (Auto) 或客户端呈现 (CSR)

按照添加静态服务器端呈现(静态 SSR)部分中的指导进行操作。

使用交互式自动呈现模式的组件最初使用交互式 SSR。 .NET 运行时和应用捆绑包会在后台下载到客户端并缓存,以便将来访问时可以使用它们。 下载 Blazor 捆绑包并激活 Blazor 运行时后,使用交互式 WebAssembly 呈现模式的组件仅在客户端上以交互方式呈现。 请记住,使用交互式自动或交互式 WebAssembly 呈现模式时,下载到客户端的组件代码不是专用的。 有关详细信息,请参阅 ASP.NET Core Blazor 呈现模式

确定要采用的呈现模式后:

Microsoft.AspNetCore.Components.WebAssembly.Server NuGet 包的包引用添加到应用。

注意

有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。

创建捐赠者 Blazor Web App 以为应用提供资产。 按照 ASP.NET Core 工具Blazor一文中的指导,在生成 Blazor Web App 时选择对以下模板功能的支持。

对于应用的名称,请使用与 ASP.NET Core 应用相同的名称,这会导致在组件中匹配应用名称标记,并在代码中匹配命名空间。 不严格要求使用相同的名称/命名空间,因为资产从捐赠者应用移动到 ASP.NET Core 应用后,可以调整命名空间。 但是,一开始就通过匹配命名空间来保存时间。

Visual Studio:

  • 对于交互式呈现模式,请选择“自动(服务器和 WebAssembly)”。
  • 将交互位置设置为“每页/组件”。
  • 取消选择包含示例页面的检查框

.NET CLI:

  • 使用 -int Auto 选项。
  • 请勿使用 -ai|--all-interactive 选项。
  • 传递 -e|--empty 选项。

在捐赠者 Blazor Web App 中,将整个 .Client 项目复制到 ASP.NET Core 应用的解决方案文件夹中。

重要

不要将 .Client 文件夹复制到 ASP.NET Core 项目的文件夹。 组织 .NET 解决方案的最佳方法是将解决方案的每个项目放入顶层解决方案文件夹内的自己的文件夹中。 如果 ASP.NET Core 项目文件夹上方的解决方案文件夹不存在,请创建一个。 接下来,将 .Client 项目的文件夹从捐赠者 Blazor Web App 复制到解决方案文件夹中。 最终项目文件夹结构应具有以下布局:

  • BlazorSampleSolution (顶级解决方案文件夹)
    • BlazorSample (原始 ASP.NET Core 项目)
    • BlazorSample.Client(来自捐赠者 Blazor Web App 的 .Client 项目文件夹)

对于 ASP.NET Core 解决方案文件,可以将该文件保留在 ASP.NET Core 项目的文件夹中。 或者,只要项目引用正确指向解决方案文件夹中两个项目的项目文件(.csproj),就可以在顶层解决方案文件夹中移动解决方案文件或创建新文件。

如果在创建捐赠者项目时将捐赠者 Blazor Web App 命名为与 ASP.NET Core 应用相同的名称,则捐赠资产使用的命名空间将与 ASP.NET Core 应用中的命名空间匹配。 无需采取进一步步骤来匹配命名空间。 如果在创建捐赠者 Blazor Web App 项目时使用了不同的命名空间,则必须调整捐赠资产中的命名空间以进行匹配(如果你打算完全按照所介绍内容使用本指南的 rest)。 如果命名空间不匹配,调整命名空间,然后再继续,按照本部分中的剩余指南调整命名空间。

删除捐赠者 Blazor Web App,因为在此过程中不再使用它。

.Client 项目添加到解决方案:

  • Visual Studio:右键单击解决方案资源管理器中的解决方案,然后选择添加>现有项目。 导航到 .Client 文件夹并选择项目文件(.csproj)。

  • .NET CLI:使用 dotnet sln add 命令.Client 项目添加到解决方案。

将 ASP.NET Core 项目中的项目引用添加到客户端项目:

  • Visual Studio:右键单击 ASP.NET Core 项目,然后选择“添加”>“项目引用”。 选择 .Client 项目,然后选择“确定”

  • .NET CLI:在 ASP.NET Core 项目的文件夹中,使用以下命令:

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

    上述命令假定为以下内容:

    • 项目文件名为 BlazorSample.Client.csproj
    • .Client 项目位于解决方案文件夹内的 BlazorSample.Client 文件夹中。 .Client 文件夹与 ASP.NET Core 项目的文件夹并排。

    有关 dotnet add reference 命令的详细信息,请参阅 dotnet add reference(.NET 文档)

对 ASP.NET Core 应用的 Program 文件进行以下更改:

  • 使用 AddInteractiveWebAssemblyComponents 添加交互式 WebAssembly 组件服务,其中 Razor 组件服务随 AddRazorComponents 一起添加。

    对于交互式自动呈现:

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

    仅对于交互式 WebAssembly 呈现:

    builder.Services.AddRazorComponents()
        .AddInteractiveWebAssemblyComponents();
    
  • .Client项目添加交互式 WebAssembly 呈现模式 (AddInteractiveWebAssemblyRenderMode) 和其他程序集,其中 Razor 组件使用 MapRazorComponents 进行映射。

    对于交互式自动 (Auto) 呈现:

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

    仅对于交互式 WebAssembly 呈现:

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

    在前面的示例中,更改 BlazorSample.Client 以匹配 .Client 项目的命名空间。

Pages 文件夹添加到 .Client 项目。

如果 ASP.NET Core 项目具有现有 Counter 组件:

  • 将组件移动到 .Client 项目的 Pages 文件夹。
  • 删除组件文件顶部的 @rendermode 指令。

如果 ASP.NET Core 应用没有 Counter 组件,请将以下 Counter 组件 (Pages/Counter.razor) 添加到 .Client 项目:

@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++;
    }
}

如果应用仅采用交互式 WebAssembly 呈现,请删除 @rendermode 指令和值:

- @rendermode InteractiveAuto

ASP.NET Core 应用 项目运行解决方案:

  • Visual Studio:确认运行应用时,解决方案资源管理器选择了 ASP.NET Core 项目。

  • .NET CLI:从 ASP.NET Core 项目的文件夹运行项目。

若要加载 Counter 组件,请导航到 /counter

实现 Blazor的布局和样式

(可选)使用 RouteView 组件的 RouteView.DefaultLayout 参数分配默认布局组件。

Routes.razor 中,以下示例使用 MainLayout 组件作为默认布局:

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

有关详细信息,请参阅 ASP.NET Core Blazor 布局

可从 dotnet/aspnetcore GitHub 存储库获取 Blazor 项目模板布局和样式表:

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

注意

指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)

根据如何在应用中组织布局文件,可能需要在应用的 _Imports.razor 文件中为布局文件的文件夹添加一个 @using 语句,以便在应用组件中使用它们。

使用 CSS 隔离时,无需显式引用样式表。 Blazor 框架会自动捆绑单个组件样式表。 应用的捆绑样式表已在应用的 App 组件({ASSEMBLY NAME}.styles.css,其中 {ASSEMBLY NAME} 占位符是应用的程序集名称)中引用。

从 MVC 控制器操作返回 RazorComponentResult

MVC 控制器操作可以返回包含 RazorComponentResult<TComponent> 的组件。

Components/Welcome.razor

<PageTitle>Welcome!</PageTitle>

<h1>Welcome!</h1>

<p>@Message</p>

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

在控制器中:

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

仅返回呈现组件的 HTML 标记。 布局和 HTML 页面标记不会随该组件自动呈现。 若要生成完整的 HTML 页面,应用可维护一个为 <html><head><body> 和其他标记提供 HTML 标记的 Blazor 布局。 对于本部分中的示例,该组件包含在组件定义文件 Welcome.razor 顶部带有 @layoutRazor 指令的布局。 以下示例假定应用具有名为 RazorComponentResultLayout 的布局 (Components/Layout/RazorComponentResultLayout.razor):

@using BlazorSample.Components.Layout
@layout RazorComponentResultLayout

通过将 Layout 文件夹的 @using 语句移动到应用的 _Imports.razor 文件中,可避免将其置于单个组件中。

有关详细信息,请参阅 ASP.NET Core Blazor 布局

组件命名空间

使用自定义文件夹保存项目的 Razor 组件时,将表示文件夹的命名空间添加到页面/视图或 _ViewImports.cshtml 文件。 如下示例中:

  • 组件存储在项目的 Components 文件夹中。
  • {APP NAMESPACE} 占位符是项目的文件夹。 Components 表示文件夹的名称。
@using {APP NAMESPACE}.Components

例如:

@using BlazorSample.Components

_ViewImports.cshtml 文件位于 Razor Pages 应用的 Pages 文件夹中,或是 MVC 应用的 Views 文件夹中。

有关详细信息,请参阅 ASP.NET Core Razor 组件

其他资源

预呈现 ASP.NET Core Razor 组件