预呈现和集成 ASP.NET Core Razor 组件

注意

此版本不是本文的最新版本。 有关本文的最新版本,请参阅 .NET 7 版本

本文介绍 Blazor 应用的 Razor 组件集成方案,包括在服务器上预呈现 Razor 组件。

重要

各 ASP.NET Core 版本中的框架更改导致本文提供了多组不同的说明。 在使用本文的指导之前,请确认本文顶部的文档版本选择器与要用于应用的 ASP.NET Core 版本匹配。

Razor 组件可以通过托管的 Blazor WebAssembly 解决方案集成到 Razor Pages 和 MVC 应用。 呈现页面或视图时,可以同时预呈现组件。

预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)

解决方案配置

预呈现配置

若要设置托管 Blazor WebAssembly 应用的预呈现,请执行以下操作:

  1. 将 Blazor WebAssembly 应用托管在 ASP.NET Core 应用中。 可以将独立的 Blazor WebAssembly 应用添加到 ASP.NET Core 解决方案中,也可以使用通过托管选项从 Blazor WebAssembly 项目模板创建的托管 Blazor WebAssembly 应用:

    • Visual Studio:在“其他信息”对话框中,创建 Blazor WebAssembly 应用时选中“托管的 ASP.NET Core”复选框。 在本文的示例中,该解决方案的名称为 BlazorHosted
    • Visual Studio Code/.NET CLI 命令行界面:dotnet new blazorwasm -ho(使用 -ho|--hosted 选项)。 使用 -o|--output {LOCATION} 选项为解决方案创建文件夹,并设置解决方案的项目命名空间。 在本文的示例中,该解决方案的名称为 BlazorHosted (dotnet new blazorwasm -ho -o BlazorHosted)。

    对于本文中的示例,托管解决方案的名称(程序集名称)为 BlazorHosted。 客户端项目的命名空间为 BlazorHosted.Client,服务器项目的命名空间为 BlazorHosted.Server

  2. 从 Blazor WebAssemblyClient 项目中删除 wwwroot/index.html 文件。

  3. Client 项目中,删除 Program.cs 中的以下行:

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  4. _Host.cshtml 文件添加到 Server 项目的 Pages 文件夹。 可以在命令行界面中使用 Visual Studio 或 .NET CLI 通过 dotnet new blazorserver -o BlazorServer 命令从 Blazor Server 模板创建的项目获取文件(-o BlazorServer 选项为项目创建一个文件夹)。 将文件放入 Server 项目的 Pages 文件夹后,对文件进行以下更改。

    _Host.cshtml 文件进行以下更改:

    • 更新文件顶部的 Pages 命名空间,使其与 Server 应用页的命名空间匹配。 以下示例中的 {APP NAMESPACE} 占位符表示提供 _Host.cshtml 文件的赞助商应用页的命名空间:

      删除:

      - @namespace {APP NAMESPACE}.Pages
      

      添加:

      @namespace BlazorHosted.Server.Pages
      
    • 在文件顶部,为 Client 项目添加 @using 指令:

      @using BlazorHosted.Client
      
    • 更新样式表链接,以指向 WebAssembly 项目的样式表。 在下面的示例中,客户端项目的命名空间为 BlazorHosted.Client{APP NAMESPACE} 占位符表示提供 _Host.cshtml 文件的赞助商应用的命名空间。 更新 HeadOutlet 组件的组件标记帮助程序(<component> 标记),以预呈现该组件。

      删除:

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

      添加:

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

      注意

      就地保留请求启动样式 (css/bootstrap/bootstrap.min.css) 表的 <link> 元素。

    • 更新 Blazor 脚本源,以使用客户端 Blazor WebAssembly 脚本:

      删除:

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

      添加:

      <script src="_framework/blazor.webassembly.js"></script>
      
    • 更新组件标记帮助程序render-mode,以使用 WebAssemblyPrerendered 预呈现根 App 组件:

      删除:

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

      添加:

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

      重要

      身份验证终结点(/authentication/ 路径段)不支持预呈现。 有关详细信息,请参阅 ASP.NET Core Blazor WebAssembly 其他安全方案

  5. Server 项目的 Program.cs 文件中,将回退终结点从 index.html 文件更改为 _Host.cshtml 页面:

    删除:

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

    添加:

    app.MapFallbackToPage("/_Host");
    
  6. 如果 ClientServer 项目在预呈现期间使用一个或多个通用服务,则将服务注册分解为可以从这两个项目调用的方法。 有关详细信息,请参阅 ASP.NET Core Blazor 依赖项注入

  7. 运行 Server 项目。 托管 Blazor WebAssembly 应用由客户端的 Server 项目预呈现。

用于将 Razor 组件嵌入到页面和视图中的配置

以下部分和示例将 ClientBlazor WebAssembly 应用的 Razor 组件嵌入到服务器应用的页面和视图中,它们需要其他配置。

Server 项目必须具有以下文件和文件夹。

Razor Pages:

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

MVC:

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

可以通过使用以下内容从 ASP.NET Core 项目模板生成应用来获取上述文件:

  • Visual Studio 的新项目创建工具。
  • 打开命令行界面,执行 dotnet new webapp -o {PROJECT NAME} (Razor Pages) 或 dotnet new mvc -o {PROJECT NAME} (MVC)。 占位符值为 {PROJECT NAME} 的选项 -o|--output 提供应用名称,并为该应用创建一个文件夹。

更新导入的 _ViewImports.cshtml 文件中的命名空间,使其与接收文件的 Server 项目所使用的命名空间相匹配。

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

更新导入的布局文件(对于 Razor Pages,为 Pages/Shared/_Layout.cshtml,对于 MVC 则为 Views/Shared/_Layout.cshtml)。

首先,从赞助商项目中删除标题和样式表,以下示例中为 RPDonor.styles.css{PROJECT NAME} 占位符表示赞助商项目的应用名称。

- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />

在布局文件中包括 Client 项目的样式。 在下面的示例中,Client 项目的命名空间为 BlazorHosted.Client。 可以同时更新的 <title> 元素。

将以下行置于布局文件的 <head> 内容中:

<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />

导入的布局包含两个导航链接 HomeIndex 页)和 Privacy。 若要使 Home 链接指向托管的 Blazor WebAssembly 应用,请更改超链接:

- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

在 MVC 布局文件中:

- <a class="navbar-brand" asp-area="" asp-controller="Home" 
-     asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <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>

更新 <footer> 元素的应用名称。 以下示例使用应用名称 BlazorHosted

- &copy; {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ &copy; {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>

在前面的示例中,{DATE} 占位符表示从 Razor Pages 或 MVC 项目模板生成的应用中的版权日期。

若要使 Privacy 链接指向 privacy 页 (Razor Pages),请将 privacy 页添加到 Server 项目。

Server 项目中的 Pages/Privacy.cshtml

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

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

对于基于 MVC 的 privacy 视图,请在 Server 项目中创建一个 privacy 视图。

Server 项目中的 View/Home/Privacy.cshtml

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

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

在 MVC 应用的 Home 控制器中,返回视图。

将下列代码添加到 Controllers/HomeController.cs

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

如果从赞助商应用导入文件,请确保更新文件中的任何命名空间,以匹配 Server 项目的命名空间(例如 BlazorHosted.Server)。

从赞助商项目的 wwwroot 文件夹中将静态资产导入到 Server 项目:

  • wwwroot/css 文件夹和内容
  • wwwroot/js 文件夹和内容
  • wwwroot/lib 文件夹和内容

如果从 ASP.NET Core 项目模板创建了赞助商项目,但未修改文件,则可以将整个 wwwroot 文件夹从赞助商项目复制到 Server 项目中,并删除 favicon 图标文件。

警告

避免将静态资产放入 ClientServer wwwroot 文件夹中。 如果这两个文件夹中存在相同文件,则会引发异常,因为静态资产共享同一个 Web 根路径。 因此,在任意一个 wwwroot 文件夹(而不是两者)中托管静态资产。

采用前面的配置后,将 Razor 组件嵌入到 Server 项目的页面或视图中。 使用本文以下部分的指南:

  • 使用组件标记帮助程序,通过页面或视图呈现组件
  • 使用 CSS 选择器,通过页面或视图呈现组件

使用组件标记帮助程序,通过页面或视图呈现组件

配置解决方案(包括其他配置)后,组件标记帮助程序支持两种呈现模式来通过页面或视图呈现 Blazor WebAssembly 应用中的组件:

在下面的 Razor Pages 示例中,页面中呈现了 Counter 组件。 页面的呈现部分包含了 Blazor WebAssembly 脚本,以使组件成为交互式组件。 为客户端项目的 Pages 命名空间添加 @using 指令,以避免将 Counter 组件的整个命名空间用于组件标记帮助程序 ({ASSEMBLY NAME}.Pages.Counter)。 在下面的示例中,Client 项目的命名空间为 BlazorHosted.Client

Server 项目中,Pages/RazorPagesCounter1.cshtml

@page
@using BlazorHosted.Client.Pages

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

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

运行 Server 项目。 导航到 /razorpagescounter1 中的 Razor 页。 预呈现的 Counter 组件嵌入在页面中。

RenderMode 配置组件是否:

  • 在页面中预呈现。
  • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

可能需要额外的工作,具体取决于组件使用的静态资源以及布局页面在应用中的组织方式。 通常,脚本添加到了页面或视图的 Scripts 呈现部分,样式表添加到了布局的 <head> 元素内容。

通过呈现片段设置子内容

组件标记帮助程序不支持接收子内容的 RenderFragment 委托(例如 param-ChildContent="...")。 我们建议创建一个 Razor 组件 (.razor),该组件引用要呈现的组件以及要传递的子内容,然后从页面或视图中调用 Razor 组件。

确保在发布时不会剪裁顶级预呈现组件

如果组件标记帮助程序直接引用库中的一个组件,而该组件在发布时需要剪裁,则组件可能会在发布期间被剪裁掉,因为客户端应用代码中没有对该组件的引用。 因此,不会预呈现组件,而是在输出中留有空白位置。 如果发生这种情况,请通过向客户端应用中的任何类添加 DynamicDependency 属性来指示剪裁器保留库组件。 若要保留名为 SomeLibraryComponentToBePreserved 的组件,请向任何组件添加以下内容:

@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All, 
    typeof(SomeLibraryComponentToBePreserved))]

上述方法通常不是必需的,因为应用通常会预呈现其组件(未剪裁),这反过来又引用库中的组件(导致它们也不会被剪裁)。 只有在库需要剪裁时,才将 DynamicDependency 显式用于直接预呈现库组件。

使用 CSS 选择器,通过页面或视图呈现组件

配置解决方案(包括其他配置)后,将根组件添加到 Program.cs 文件中的托管 Blazor WebAssembly 解决方案的 Client 项目。 下面的示例使用 CSS 选择器将 Counter 组件声明为根组件,该选择器会选择 idcounter-component 匹配的元素。 在下面的示例中,Client 项目的命名空间为 BlazorHosted.Client

Client 项目的 Program.cs 文件中,将项目的 Razor 组件的命名空间添加到文件顶部:

using BlazorHosted.Client.Pages;

Program.cs 中建立 builder 后,将 Counter 组件添加为根组件:

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

在下面的 Razor Pages 示例中,页面中呈现了 Counter 组件。 页面的呈现部分包含了 Blazor WebAssembly 脚本,以使组件成为交互式组件。

Server 项目中,Pages/RazorPagesCounter2.cshtml

@page

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

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

运行 Server 项目。 导航到 /razorpagescounter2 中的 Razor 页。 预呈现的 Counter 组件嵌入在页面中。

可能需要额外的工作,具体取决于组件使用的静态资源以及布局页面在应用中的组织方式。 通常,脚本添加到了页面或视图的 Scripts 呈现部分,样式表添加到了布局的 <head> 元素内容。

注意

如果 Blazor WebAssembly 应用已预呈现,并且使用 CSS 选择器同时集成到 Razor Pages 或 MVC 应用中,则前面的示例将引发 JSException。 如果导航到 Client 项目的 Razor 组件之一,或者导航到具有嵌入组件的 Server 的页面或视图,会引发一个或多个 JSException

这是正常行为,因为预呈现和集成具有可路由 Razor 组件的 Blazor WebAssembly 应用与使用 CSS 选择器不兼容。

如果你一直在使用前面部分中的示例,并且只想看到 CSS 选择器在示例应用中工作,请注释掉 Client 项目 Program.cs 文件的 App 根组件的规范:

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

通过使用 CSS 选择器的嵌入式 Razor 组件(例如前面示例的 /razorpagescounter2)导航到页面或视图。 页面或视图随嵌入式组件一起加载,而嵌入式组件按预期运行。

Razor 组件可以集成到 Razor Pages 和 MVC 应用。 呈现页面或视图时,可以同时预呈现组件。

预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)

配置项目后,根据项目的要求按照下列部分中的指南操作:

Configuration

使用以下指南将 Razor 组件集成到现有 Razor Pages 或 MVC 应用的页面和视图中。

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

    _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}
    
  2. 在项目的布局文件(Razor Pages 应用中的 Pages/Shared/_Layout.cshtml 或 MVC 应用中的 Views/Shared/_Layout.cshtml)中:

    • 将以下 <base> 标记和 HeadOutlet 组件标记帮助程序添加到 <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.server.js 脚本添加 <script> 标记:

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

      框架会将 blazor.server.js 脚本添加到应用。 无需手动将 blazor.server.js 脚本文件添加到应用。

    注意

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

  3. 在注册服务的 Program.cs 中注册 Blazor Server 服务:

    builder.Services.AddServerSideBlazor();
    
  4. 将 Blazor 中心终结点添加到映射路由的 Program.cs 的终结点。 在调用 MapRazorPages (RazorPages) 或 MapControllerRoute (MVC) 后放置以下行:

    app.MapBlazorHub();
    
  5. 将组件集成到任何页面或视图。 例如,将 Counter 组件添加到项目的 Shared 文件夹。

    Pages/Shared/Counter.razor (Razor Pages) 或 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:

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

    Pages/Index.cshtml:

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

    MVC:

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

    Views/Home/Index.cshtml:

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

有关详细信息,请参阅从页面或视图呈现组件部分。

在 Razor Pages 应用中使用可路由组件

本部分介绍如何添加可直接从用户请求路由的组件。

在 Razor Pages 应用中支持可路由 Razor 组件:

  1. 按照配置部分中的指南操作。

  2. 将具有以下内容的 App 组件添加到项目根。

    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. 将具有以下内容的 _Host 页面添加到项目。 使用应用的命名空间替换 {APP NAMESPACE} 占位符。

    Pages/_Host.cshtml:

    @page
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    注意

    前面的示例假定 HeadOutlet 组件和 Blazor 脚本 (_framework/blazor.server.js) 由应用的布局呈现。 有关详细信息,请参阅配置部分。

    RenderMode 会配置 App 组件是否:

    • 在页面中预呈现。
    • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

    有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

  4. Program.cs 终结点中,将 _Host 页面的低优先级路由添加为最后一个终结点:

    app.MapFallbackToPage("/_Host");
    
  5. 将可路由组件添加到项目。 以下示例是 RoutableCounter 组件,它基于 Blazor 项目模板中的 Counter 组件。

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <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. 运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。

有关命名空间的详细信息,请参阅组件命名空间部分。

在 MVC 应用中使用可路由组件

本部分介绍如何添加可直接从用户请求路由的组件。

在 MVC 应用中支持可路由 Razor 组件:

  1. 按照配置部分中的指南操作。

  2. 将具有以下内容的 App 组件添加到项目根。

    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. 将具有以下内容的 _Host 视图添加到项目。 使用应用的命名空间替换 {APP NAMESPACE} 占位符。

    Views/Home/_Host.cshtml:

    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    注意

    前面的示例假定 HeadOutlet 组件和 Blazor 脚本 (_framework/blazor.server.js) 由应用的布局呈现。 有关详细信息,请参阅配置部分。

    RenderMode 会配置 App 组件是否:

    • 在页面中预呈现。
    • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

    有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

  4. 向 Home 控制器添加操作。

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. Program.cs 终结点中,为返回 _Host 视图的控制器操作添加一个低优先级路由:

    app.MapFallbackToController("Blazor", "Home");
    
  6. 在 MVC 应用中创建一个 Pages 文件夹,并添加可路由的组件。 以下示例是 RoutableCounter 组件,它基于 Blazor 项目模板中的 Counter 组件。

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <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. 运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。

有关命名空间的详细信息,请参阅组件命名空间部分。

从页面或视图呈现组件

本部分介绍如何在无法从用户请求直接路由组件的情况下,将组件添加到页面或视图。

若要从页面或视图呈现组件,请使用组件标记帮助程序

呈现有状态交互式组件

可以将有状态的交互式组件添加到 Razor 页面或视图。

呈现页面或视图时:

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

以下 Razor 页面将呈现 Counter 组件:

<h1>Razor Page</h1>

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

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

有关详细信息,请参阅 ASP.NET Core 中的组件标记帮助程序

呈现非交互式组件

在以下 Razor 页面中,使用以下格式通过指定的初始值静态呈现 Counter 组件。 由于该组件是以静态方式呈现的,因此它不是交互式组件:

<h1>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; }
}

有关详细信息,请参阅 ASP.NET Core 中的组件标记帮助程序

组件命名空间

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

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

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

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

保留预呈现状态

在不保留预呈现状态的情况下,在预呈现期间使用的状态将丢失,并且在完全加载应用时必须重新创建。 如果任何状态都是异步设置的,则 UI 可能会闪烁,因为预呈现 UI 将替换为临时占位符,然后再次完全呈现。

要保留预呈现组件的状态,请使用“保留组件状态”标记帮助程序参考源)。 在预呈现组件的应用的 _Host 页面的结束 </body> 标记内添加标记帮助程序的标记 <persist-component-state />

注意

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

在 Blazor 应用(托管 Blazor WebAssembly 应用中预呈现的 WebAssembly (WebAssemblyPrerendered),或 Blazor Server 应用中的 ServerPrerendered)的 Pages/_Host.cshtml 中:

<body>
    ...

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

决定要使用 PersistentComponentState 服务保留的状态。 PersistentComponentState.RegisterOnPersisting 注册回调以在暂停应用之前保留组件状态。 在应用程序恢复时检索状态。

如下示例中:

  • {TYPE} 占位符表示要持久保存的数据类型(例如 WeatherForecast[])。
  • {TOKEN} 占位符是状态标识符字符串(例如 fetchdata)。
@implements IDisposable
@inject PersistentComponentState ApplicationState

...

@code {
    private {TYPE} data;
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistData);

        if (!ApplicationState.TryTakeFromJson<{TYPE}>(
            "{TOKEN}", out var restored))
        {
            data = await ...;
        }
        else
        {
            data = restored!;
        }
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson("{TOKEN}", data);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

以下示例是基于 Blazor 项目模板的托管的 Blazor WebAssembly 应用中 FetchData 组件的更新版本。 WeatherForecastPreserveState 组件在预呈现期间保留天气预报状态,然后检索状态以初始化组件。 保留组件状态标记帮助程序在所有组件调用之后保留组件状态。

Pages/WeatherForecastPreserveState.razor:

@page "/weather-forecast-preserve-state"
@using BlazorSample.Shared
@implements IDisposable
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState

<PageTitle>Weather Forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistForecasts);

        if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
            "fetchdata", out var restored))
        {
            forecasts = 
                await WeatherForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now));
        }
        else
        {
            forecasts = restored!;
        }
    }

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

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

通过使用在预呈现期间使用的相同状态来初始化组件,将只执行一次成本高昂的初始化步骤。 呈现的 UI 也与预呈现 UI 相匹配,因此浏览器不会闪烁。

持久预呈现状态将传输到客户端,用于还原组件状态。 ASP.NET 核心数据保护 可确保在应用中安全地 Blazor Server 传输数据。 对于托管 Blazor WebAssembly 应用中的预呈现,数据将公开给浏览器,并且不得包含敏感的私有信息。

其他 Blazor WebAssembly 资源

预呈现状态大小和 SignalR 消息大小限制

较大的预呈现状态大小可能会超出 SignalR 线路消息大小限制,从而导致以下结果:

  • SignalR 线路初始化失败,客户端上出现错误:Circuit host not initialized.
  • 当线路发生故障时,客户端上显示重新连接 UI。 无法进行恢复。

若要解决此问题,请使用以下任一方法

  • 减少要置于预呈现状态的数据量。
  • 增加 SignalR 消息大小限制。 警告:增加限制可能会增加拒绝服务 (DoS) 攻击风险

其他 Blazor Server 资源

Razor 组件可以通过托管的 Blazor WebAssembly 解决方案集成到 Razor Pages 和 MVC 应用。 呈现页面或视图时,可以同时预呈现组件。

预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)

解决方案配置

预呈现配置

若要设置托管 Blazor WebAssembly 应用的预呈现,请执行以下操作:

  1. 将 Blazor WebAssembly 应用托管在 ASP.NET Core 应用中。 可以将独立的 Blazor WebAssembly 应用添加到 ASP.NET Core 解决方案中,也可以使用通过托管选项从 Blazor WebAssembly 项目模板创建的托管 Blazor WebAssembly 应用:

    • Visual Studio:在“其他信息”对话框中,创建 Blazor WebAssembly 应用时选中“托管的 ASP.NET Core”复选框。 在本文的示例中,该解决方案的名称为 BlazorHosted
    • Visual Studio Code/.NET CLI 命令行界面:dotnet new blazorwasm -ho(使用 -ho|--hosted 选项)。 使用 -o|--output {LOCATION} 选项为解决方案创建文件夹,并设置解决方案的项目命名空间。 在本文的示例中,该解决方案的名称为 BlazorHosted (dotnet new blazorwasm -ho -o BlazorHosted)。

    对于本文中的示例,客户端项目的命名空间为 BlazorHosted.Client,服务器项目的命名空间为 BlazorHosted.Server

  2. 从 Blazor WebAssemblyClient 项目中删除 wwwroot/index.html 文件。

  3. Client 项目中,删除 Program.cs 中的以下行:

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  4. _Host.cshtml_Layout.cshtml 文件添加到 Server 项目的 Pages 文件夹。 可以在命令行界面中使用 Visual Studio 或 .NET CLI 通过 dotnet new blazorserver -o BlazorServer 命令从 Blazor Server 模板创建的项目获取文件(-o BlazorServer 选项为项目创建一个文件夹)。 将文件放入 Server 项目的 Pages 文件夹后,对文件进行以下更改。

    重要

    需要将布局页 (_Layout.cshtml) 和 HeadOutlet 组件的组件标记帮助程序一起使用来控制 <head> 内容,例如页面标题(PageTitle 组件)和其他头元素(HeadContent 组件)。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制头内容

    _Layout.cshtml 文件进行以下更改:

    • 更新文件顶部的 Pages 命名空间,使其与 Server 应用页的命名空间匹配。 以下示例中的 {APP NAMESPACE} 占位符表示提供 _Layout.cshtml 文件的赞助商应用页的命名空间:

      删除:

      - @namespace {APP NAMESPACE}.Pages
      

      添加:

      @namespace BlazorHosted.Server.Pages
      
    • 在文件顶部,为 Client 项目添加 @using 指令:

      @using BlazorHosted.Client
      
    • 更新样式表链接,以指向 WebAssembly 项目的样式表。 在下面的示例中,客户端项目的命名空间为 BlazorHosted.Client{APP NAMESPACE} 占位符表示提供 _Layout.cshtml 文件的赞助商应用的命名空间。 更新 HeadOutlet 组件的组件标记帮助程序(<component> 标记),以预呈现该组件。

      删除:

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

      添加:

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

      注意

      就地保留请求启动样式 (css/bootstrap/bootstrap.min.css) 表的 <link> 元素。

    • 更新 Blazor 脚本源,以使用客户端 Blazor WebAssembly 脚本:

      删除:

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

      添加:

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

    _Host.cshtml 文件中:

    • Pages 命名空间更改为 Client 项目的命名空间。 {APP NAMESPACE} 占位符表示提供 _Host.cshtml 文件的赞助商应用页的命名空间:

      删除:

      - @namespace {APP NAMESPACE}.Pages
      

      添加:

      @namespace BlazorHosted.Client
      
    • 更新组件标记帮助程序render-mode,以使用 WebAssemblyPrerendered 预呈现根 App 组件:

      删除:

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

      添加:

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

      重要

      身份验证终结点(/authentication/ 路径段)不支持预呈现。 有关详细信息,请参阅 ASP.NET Core Blazor WebAssembly 其他安全方案

  5. ServerProgram.cs 项目的终结点映射中,将回退从 index.html 文件更改为 _Host.cshtml 页面:

    删除:

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

    添加:

    app.MapFallbackToPage("/_Host");
    
  6. 如果 ClientServer 项目在预呈现期间使用一个或多个通用服务,则将服务注册分解为可以从这两个项目调用的方法。 有关详细信息,请参阅 ASP.NET Core Blazor 依赖项注入

  7. 运行 Server 项目。 托管 Blazor WebAssembly 应用由客户端的 Server 项目预呈现。

用于将 Razor 组件嵌入到页面和视图中的配置

以下部分和示例将 ClientBlazor WebAssembly 应用的 Razor 组件嵌入到服务器应用的页面和视图中,它们需要其他配置。

Server 项目必须具有以下文件和文件夹。

Razor Pages:

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

MVC:

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

重要

需要将布局页 (_Layout.cshtml) 和 HeadOutlet 组件的组件标记帮助程序一起使用来控制 <head> 内容,例如页面标题(PageTitle 组件)和其他头元素(HeadContent 组件)。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制头内容

可以通过使用以下内容从 ASP.NET Core 项目模板生成应用来获取上述文件:

  • Visual Studio 的新项目创建工具。
  • 打开命令行界面,执行 dotnet new webapp -o {PROJECT NAME} (Razor Pages) 或 dotnet new mvc -o {PROJECT NAME} (MVC)。 占位符值为 {PROJECT NAME} 的选项 -o|--output 提供应用名称,并为该应用创建一个文件夹。

更新导入的 _ViewImports.cshtml 文件中的命名空间,使其与接收文件的 Server 项目所使用的命名空间相匹配。

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

更新导入的布局文件(对于 Razor Pages,为 Pages/Shared/_Layout.cshtml,对于 MVC 则为 Views/Shared/_Layout.cshtml)。

首先,从赞助商项目中删除标题和样式表,以下示例中为 RPDonor.styles.css{PROJECT NAME} 占位符表示赞助商项目的应用名称。

- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />

在布局文件中包括 Client 项目的样式。 在下面的示例中,Client 项目的命名空间为 BlazorHosted.Client。 可以同时更新的 <title> 元素。

将以下行置于布局文件的 <head> 内容中:

<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />

导入的布局包含两个导航链接 HomeIndex 页)和 Privacy。 若要使 Home 链接指向托管的 Blazor WebAssembly 应用,请更改超链接:

- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

在 MVC 布局文件中:

- <a class="navbar-brand" asp-area="" asp-controller="Home" 
-     asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <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>

更新 <footer> 元素的应用名称。 以下示例使用应用名称 BlazorHosted

- &copy; {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ &copy; {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>

在前面的示例中,{DATE} 占位符表示从 Razor Pages 或 MVC 项目模板生成的应用中的版权日期。

若要使 Privacy 链接指向 privacy 页 (Razor Pages),请将 privacy 页添加到 Server 项目。

Server 项目中的 Pages/Privacy.cshtml

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

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

对于基于 MVC 的 privacy 视图,请在 Server 项目中创建一个 privacy 视图。

Server 项目中的 View/Home/Privacy.cshtml

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

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

在 MVC 应用的 Home 控制器中,返回视图。

将下列代码添加到 Controllers/HomeController.cs

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

如果从赞助商应用导入文件,请确保更新文件中的任何命名空间,以匹配 Server 项目的命名空间(例如 BlazorHosted.Server)。

从赞助商项目的 wwwroot 文件夹中将静态资产导入到 Server 项目:

  • wwwroot/css 文件夹和内容
  • wwwroot/js 文件夹和内容
  • wwwroot/lib 文件夹和内容

如果从 ASP.NET Core 项目模板创建了赞助商项目,但未修改文件,则可以将整个 wwwroot 文件夹从赞助商项目复制到 Server 项目中,并删除 favicon 图标文件。

警告

避免将静态资产放入 ClientServer wwwroot 文件夹中。 如果这两个文件夹中存在相同文件,则会引发异常,因为每个文件夹中的静态资产共享同一个 Web 根路径。 因此,在任意一个 wwwroot 文件夹(而不是两者)中托管静态资产。

采用前面的配置后,将 Razor 组件嵌入到 Server 项目的页面或视图中。 使用本文以下部分的指南:

  • 使用组件标记帮助程序,通过页面或视图呈现组件
  • 使用 CSS 选择器,通过页面或视图呈现组件

使用组件标记帮助程序,通过页面或视图呈现组件

配置解决方案(包括其他配置)后,组件标记帮助程序支持两种呈现模式来通过页面或视图呈现 Blazor WebAssembly 应用中的组件:

在下面的 Razor Pages 示例中,页面中呈现了 Counter 组件。 页面的呈现部分包含了 Blazor WebAssembly 脚本,以使组件成为交互式组件。 为客户端项目的 Pages 命名空间添加 @using 指令,以避免将 Counter 组件的整个命名空间用于组件标记帮助程序 ({ASSEMBLY NAME}.Pages.Counter)。 在下面的示例中,Client 项目的命名空间为 BlazorHosted.Client

Server 项目中,Pages/RazorPagesCounter1.cshtml

@page
@using BlazorHosted.Client.Pages

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

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

运行 Server 项目。 导航到 /razorpagescounter1 中的 Razor 页。 预呈现的 Counter 组件嵌入在页面中。

RenderMode 配置组件是否:

  • 在页面中预呈现。
  • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

可能需要额外的工作,具体取决于组件使用的静态资源以及布局页面在应用中的组织方式。 通常,脚本添加到了页面或视图的 Scripts 呈现部分,样式表添加到了布局的 <head> 元素内容。

通过呈现片段设置子内容

组件标记帮助程序不支持接收子内容的 RenderFragment 委托(例如 param-ChildContent="...")。 我们建议创建一个 Razor 组件 (.razor),该组件引用要呈现的组件以及要传递的子内容,然后从页面或视图中调用 Razor 组件。

确保在发布时不会剪裁顶级预呈现组件

如果组件标记帮助程序直接引用库中的一个组件,而该组件在发布时需要剪裁,则组件可能会在发布期间被剪裁掉,因为客户端应用代码中没有对该组件的引用。 因此,不会预呈现组件,而是在输出中留有空白位置。 如果发生这种情况,请通过向客户端应用中的任何类添加 DynamicDependency 属性来指示剪裁器保留库组件。 若要保留名为 SomeLibraryComponentToBePreserved 的组件,请向任何组件添加以下内容:

@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All, 
    typeof(SomeLibraryComponentToBePreserved))]

上述方法通常不是必需的,因为应用通常会预呈现其组件(未剪裁),这反过来又引用库中的组件(导致它们也不会被剪裁)。 只有在库需要剪裁时,才将 DynamicDependency 显式用于直接预呈现库组件。

使用 CSS 选择器,通过页面或视图呈现组件

配置解决方案(包括其他配置)后,将根组件添加到 Program.cs 文件中的托管 Blazor WebAssembly 解决方案的 Client 项目。 下面的示例使用 CSS 选择器将 Counter 组件声明为根组件,该选择器会选择 idcounter-component 匹配的元素。 在下面的示例中,Client 项目的命名空间为 BlazorHosted.Client

Client 项目的 Program.cs 文件中,将项目的 Razor 组件的命名空间添加到文件顶部:

using BlazorHosted.Client.Pages;

Program.cs 中建立 builder 后,将 Counter 组件添加为根组件:

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

在下面的 Razor Pages 示例中,页面中呈现了 Counter 组件。 页面的呈现部分包含了 Blazor WebAssembly 脚本,以使组件成为交互式组件。

Server 项目中,Pages/RazorPagesCounter2.cshtml

@page

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

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

运行 Server 项目。 导航到 /razorpagescounter2 中的 Razor 页。 预呈现的 Counter 组件嵌入在页面中。

可能需要额外的工作,具体取决于组件使用的静态资源以及布局页面在应用中的组织方式。 通常,脚本添加到了页面或视图的 Scripts 呈现部分,样式表添加到了布局的 <head> 元素内容。

注意

如果 Blazor WebAssembly 应用已预呈现,并且使用 CSS 选择器同时集成到 Razor Pages 或 MVC 应用中,则前面的示例将引发 JSException。 如果导航到 Client 项目的 Razor 组件之一,或者导航到具有嵌入组件的 Server 的页面或视图,会引发一个或多个 JSException

这是正常行为,因为预呈现和集成具有可路由 Razor 组件的 Blazor WebAssembly 应用与使用 CSS 选择器不兼容。

如果你一直在使用前面部分中的示例,并且只想看到 CSS 选择器在示例应用中工作,请注释掉 Client 项目 Program.cs 文件的 App 根组件的规范:

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

通过使用 CSS 选择器的嵌入式 Razor 组件(例如前面示例的 /razorpagescounter2)导航到页面或视图。 页面或视图随嵌入式组件一起加载,而嵌入式组件按预期运行。

Razor 组件可以集成到 Razor Pages 和 MVC 应用。 呈现页面或视图时,可以同时预呈现组件。

预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)

配置项目后,根据项目的要求按照下列部分中的指南操作:

Configuration

使用以下指南将 Razor 组件集成到现有 Razor Pages 或 MVC 应用的页面和视图中。

重要

需要将布局页 (_Layout.cshtml) 和 HeadOutlet 组件的组件标记帮助程序一起使用来控制 <head> 内容,例如页面标题(PageTitle 组件)和其他头元素(HeadContent 组件)。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制头内容

  1. 在项目的布局文件中:

    • 将以下 <base> 标记和 HeadOutlet 组件标记帮助程序添加到 Pages/Shared/_Layout.cshtml (Razor Pages) 或 Views/Shared/_Layout.cshtml (MVC) 中的 <head> 元素:

      <base href="~/" />
      <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
      

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

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

    • 在紧接着应用布局的 Scripts 呈现部分 (@await RenderSectionAsync(...)) 的前方为 blazor.server.js 脚本添加 <script> 标记。

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

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

      框架会将 blazor.server.js 脚本添加到应用。 无需手动将 blazor.server.js 脚本文件添加到应用。

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

    _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. 在注册服务的 Program.cs 中注册 Blazor Server 服务:

    builder.Services.AddServerSideBlazor();
    
  4. 将 Blazor 中心终结点添加到映射路由的 Program.cs 的终结点。

    在调用 MapRazorPages (RazorPages) 或 MapControllerRoute (MVC) 后放置以下行:

    app.MapBlazorHub();
    
  5. 将组件集成到任何页面或视图。 例如,将 Counter 组件添加到项目的 Shared 文件夹。

    Pages/Shared/Counter.razor (Razor Pages) 或 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:

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

    Pages/Index.cshtml:

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

    MVC:

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

    Views/Home/Index.cshtml:

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

有关详细信息,请参阅从页面或视图呈现组件部分。

在 Razor Pages 应用中使用可路由组件

本部分介绍如何添加可直接从用户请求路由的组件。

在 Razor Pages 应用中支持可路由 Razor 组件:

  1. 按照配置部分中的指南操作。

  2. 将具有以下内容的 App 组件添加到项目根。

    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. 将具有以下内容的 _Host 页面添加到项目。

    Pages/_Host.cshtml:

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

    在此场景中,组件将共享 _Layout.cshtml 文件用于布局。

    重要

    需要将布局页 (_Layout.cshtml) 和 HeadOutlet 组件的组件标记帮助程序一起使用来控制 <head> 内容,例如页面标题(PageTitle 组件)和其他头元素(HeadContent 组件)。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制头内容

    RenderMode 会配置 App 组件是否:

    • 在页面中预呈现。
    • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

    有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

  4. Program.cs 终结点中,将 _Host 页面的低优先级路由添加为最后一个终结点:

    app.MapFallbackToPage("/_Host");
    
  5. 将可路由组件添加到项目。 以下示例是 RoutableCounter 组件,它基于 Blazor 项目模板中的 Counter 组件。

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <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. 运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。

有关命名空间的详细信息,请参阅组件命名空间部分。

在 MVC 应用中使用可路由组件

本部分介绍如何添加可直接从用户请求路由的组件。

在 MVC 应用中支持可路由 Razor 组件:

  1. 按照配置部分中的指南操作。

  2. 将具有以下内容的 App 组件添加到项目根。

    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. 将具有以下内容的 _Host 视图添加到项目。

    Views/Home/_Host.cshtml:

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

    组件将共享 _Layout.cshtml 文件用于布局。

    重要

    需要将布局页 (_Layout.cshtml) 和 HeadOutlet 组件的组件标记帮助程序一起使用来控制 <head> 内容,例如页面标题(PageTitle 组件)和其他头元素(HeadContent 组件)。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制头内容

    RenderMode 会配置 App 组件是否:

    • 在页面中预呈现。
    • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

    有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

  4. 向 Home 控制器添加操作。

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. Program.cs 终结点中,为返回 _Host 视图的控制器操作添加一个低优先级路由:

    app.MapFallbackToController("Blazor", "Home");
    
  6. 在 MVC 应用中创建一个 Pages 文件夹,并添加可路由的组件。 以下示例是 RoutableCounter 组件,它基于 Blazor 项目模板中的 Counter 组件。

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <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. 运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。

有关命名空间的详细信息,请参阅组件命名空间部分。

从页面或视图呈现组件

本部分介绍如何在无法从用户请求直接路由组件的情况下,将组件添加到页面或视图。

若要从页面或视图呈现组件,请使用组件标记帮助程序

呈现有状态交互式组件

可以将有状态的交互式组件添加到 Razor 页面或视图。

呈现页面或视图时:

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

以下 Razor 页面将呈现 Counter 组件:

<h1>Razor Page</h1>

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

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

有关详细信息,请参阅 ASP.NET Core 中的组件标记帮助程序

重要

需要将布局页 (_Layout.cshtml) 和 HeadOutlet 组件的组件标记帮助程序一起使用来控制 <head> 内容,例如页面标题(PageTitle 组件)和其他头元素(HeadContent 组件)。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制头内容

呈现非交互式组件

在以下 Razor 页面中,使用以下格式通过指定的初始值静态呈现 Counter 组件。 由于该组件是以静态方式呈现的,因此它不是交互式组件:

<h1>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; }
}

有关详细信息,请参阅 ASP.NET Core 中的组件标记帮助程序

重要

需要将布局页 (_Layout.cshtml) 和 HeadOutlet 组件的组件标记帮助程序一起使用来控制 <head> 内容,例如页面标题(PageTitle 组件)和其他头元素(HeadContent 组件)。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制头内容

组件命名空间

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

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

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

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

保留预呈现状态

在不保留预呈现状态的情况下,在预呈现期间使用的状态将丢失,并且在完全加载应用时必须重新创建。 如果任何状态都是异步设置的,则 UI 可能会闪烁,因为预呈现 UI 将替换为临时占位符,然后再次完全呈现。

为了解决这些问题,Blazor 使用预留组件状态标记帮助程序在预呈现页面中支持持久化状态。 在结束 </body> 标记中添加标记帮助程序的标记 <persist-component-state />

Pages/_Layout.cshtml:

<body>
    ...

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

决定要使用 PersistentComponentState 服务保留的状态。 PersistentComponentState.RegisterOnPersisting 注册回调以在暂停应用之前保留组件状态。 在应用程序恢复时检索状态。

以下示例是基于 Blazor 项目模板的托管的 Blazor WebAssembly 应用中 FetchData 组件的更新版本。 WeatherForecastPreserveState 组件在预呈现期间保留天气预报状态,然后检索状态以初始化组件。 保留组件状态标记帮助程序在所有组件调用之后保留组件状态。

Pages/WeatherForecastPreserveState.razor:

@page "/weather-forecast-preserve-state"
@implements IDisposable
@using BlazorSample.Shared
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState

<PageTitle>Weather Forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistForecasts);

        if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
            "fetchdata", out var restored))
        {
            forecasts = 
                await WeatherForecastService.GetForecastAsync(DateTime.Now);
        }
        else
        {
            forecasts = restored!;
        }
    }

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

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

通过使用在预呈现期间使用的相同状态来初始化组件,将只执行一次成本高昂的初始化步骤。 呈现的 UI 也与预呈现 UI 相匹配,因此浏览器不会闪烁。

持久预呈现状态将传输到客户端,用于还原组件状态。 ASP.NET 核心数据保护 可确保在应用中安全地 Blazor Server 传输数据。 对于托管 Blazor WebAssembly 应用中的预呈现,数据将公开给浏览器,并且不得包含敏感的私有信息。

其他 Blazor WebAssembly 资源

预呈现状态大小和 SignalR 消息大小限制

较大的预呈现状态大小可能会超出 SignalR 线路消息大小限制,从而导致以下结果:

  • SignalR 线路初始化失败,客户端上出现错误:Circuit host not initialized.
  • 当线路发生故障时,客户端上显示重新连接 UI。 无法进行恢复。

若要解决此问题,请使用以下任一方法

  • 减少要置于预呈现状态的数据量。
  • 增加 SignalR 消息大小限制。 警告:增加限制可能会增加拒绝服务 (DoS) 攻击风险

其他 Blazor Server 资源

Razor 组件可以通过托管的 Blazor WebAssembly解决方案集成到 Razor Pages 和 MVC 应用。 呈现页面或视图时,可以同时预呈现组件。

预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)

解决方案配置

预呈现配置

若要设置托管 Blazor WebAssembly 应用的预呈现,请执行以下操作:

  1. 将 Blazor WebAssembly 应用托管在 ASP.NET Core 应用中。 可以将独立的 Blazor WebAssembly 应用添加到 ASP.NET Core 解决方案中,也可以使用通过托管选项从 Blazor WebAssembly 项目模板创建的托管 Blazor WebAssembly 应用:

    • Visual Studio:在“其他信息”对话框中,创建 Blazor WebAssembly 应用时选中“托管的 ASP.NET Core”复选框。 在本文的示例中,该解决方案的名称为 BlazorHosted
    • Visual Studio Code/.NET CLI 命令行界面:dotnet new blazorwasm -ho(使用 -ho|--hosted 选项)。 使用 -o|--output {LOCATION} 选项为解决方案创建文件夹,并设置解决方案的项目命名空间。 在本文的示例中,该解决方案的名称为 BlazorHosted (dotnet new blazorwasm -ho -o BlazorHosted)。

    对于本文中的示例,客户端项目的命名空间为 BlazorHosted.Client,服务器项目的命名空间为 BlazorHosted.Server

  2. 从 Blazor WebAssemblyClient 项目中删除 wwwroot/index.html 文件。

  3. Client 项目中,删除 Program.cs 中的以下行:

    - builder.RootComponents.Add<App>("#app");
    
  4. Pages/_Host.cshtml 文件添加到 Server 项目的 Pages 文件夹。 可以使用命令行界面中的 dotnet new blazorserver -o BlazorServer 命令获得 Blazor Server 模板创建的项目的 _Host.cshtml 文件(-o BlazorServer 选项为项目创建文件夹)。 将 Pages/_Host.cshtml 文件放入托管的 Blazor WebAssembly 解决方案的 Server 项目后,对此文件进行以下更改:

    • Client 项目提供 @using 指令(例如 @using BlazorHosted.Client)。

    • 更新样式表链接,以指向 WebAssembly 项目的样式表。 在下面的示例中,客户端项目的命名空间为 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" />
      

      注意

      就地保留请求启动样式 (css/bootstrap/bootstrap.min.css) 表的 <link> 元素。

    • 更新组件标记帮助程序render-mode,以使用 WebAssemblyPrerendered 预呈现根 App 组件:

      - <component type="typeof(App)" render-mode="ServerPrerendered" />
      + <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
      
    • 更新 Blazor 脚本源,以使用客户端 Blazor WebAssembly 脚本:

      - <script src="_framework/blazor.server.js"></script>
      + <script src="_framework/blazor.webassembly.js"></script>
      
  5. Server 项目的 Startup.Configure 中,将回退从 index.html 文件更改为 _Host.cshtml 页面。

    Startup.cs:

    - endpoints.MapFallbackToFile("index.html");
    + endpoints.MapFallbackToPage("/_Host");
    
  6. 如果 ClientServer 项目在预呈现期间使用一个或多个通用服务,则将服务注册分解为可以从这两个项目调用的方法。 有关详细信息,请参阅 ASP.NET Core Blazor 依赖项注入

  7. 运行 Server 项目。 托管 Blazor WebAssembly 应用由客户端的 Server 项目预呈现。

用于将 Razor 组件嵌入到页面和视图中的配置

本文中将客户端 Razor 应用的 Blazor WebAssembly 组件嵌入到服务器应用的页面和视图中的以下部分和示例需要其他配置。

使用 Server 项目中的默认 Razor Pages 或 MVC 布局文件。 Server 项目必须具有以下文件和文件夹。

Razor Pages:

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

MVC:

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

从 Razor Pages 或 MVC 项目模板创建的应用获取上述文件。 有关详细信息,请参阅教程:在 ASP.NET Core 中开始使用 Razor Pages开始使用 ASP.NET Core MVC

更新导入的 _ViewImports.cshtml 文件中的命名空间,使其与接收文件的 Server 项目所使用的命名空间相匹配。

更新导入的布局文件 (_Layout.cshtml) 以包含 Client 项目的样式。 在下面的示例中,Client 项目的命名空间为 BlazorHosted.Client。 可以同时更新的 <title> 元素。

Pages/Shared/_Layout.cshtml (Razor Pages) 或 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>

导入的布局包含 HomePrivacy 导航链接。 若要使 Home 链接指向托管 Blazor WebAssembly 应用,请更改超链接:

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

在 MVC 布局文件中:

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

若要使 Privacy 链接指向 privacy 页,请将 privacy 页添加到 Server 项目。

Server 项目中的 Pages/Privacy.cshtml

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

<h1>Privacy Policy</h1>

如果首选基于 MVC 的 privacy 视图,请在 Server 项目中创建 privacy 视图。

View/Home/Privacy.cshtml:

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

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

Home 控制器中,返回视图。

Controllers/HomeController.cs:

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

从赞助商项目的 wwwroot 文件夹中将静态资产导入到 Server 项目:

  • wwwroot/css 文件夹和内容
  • wwwroot/js 文件夹和内容
  • wwwroot/lib 文件夹和内容

如果从 ASP.NET Core 项目模板创建了赞助商项目,但未修改文件,则可以将整个 wwwroot 文件夹从赞助商项目复制到 Server 项目中,并删除 favicon 图标文件。

警告

避免将静态资产放入 ClientServer wwwroot 文件夹中。 如果这两个文件夹中存在相同文件,则会引发异常,因为每个文件夹中的静态资产共享同一个 Web 根路径。 因此,在任意一个 wwwroot 文件夹(而不是两者)中托管静态资产。

使用组件标记帮助程序,通过页面或视图呈现组件

配置解决方案(包括其他配置)后,组件标记帮助程序支持两种呈现模式来通过页面或视图呈现 Blazor WebAssembly 应用中的组件:

在下面的 Razor Pages 示例中,页面中呈现了 Counter 组件。 页面的呈现部分包含了 Blazor WebAssembly 脚本,以使组件成为交互式组件。 为客户端项目的 Pages 命名空间添加 @using 指令,以避免将 Counter 组件的整个命名空间用于组件标记帮助程序 ({ASSEMBLY NAME}.Pages.Counter)。 在下面的示例中,Client 项目的命名空间为 BlazorHosted.Client

Server 项目中,Pages/RazorPagesCounter1.cshtml

@page
@using BlazorHosted.Client.Pages

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

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

运行 Server 项目。 导航到 /razorpagescounter1 中的 Razor 页。 预呈现的 Counter 组件嵌入在页面中。

RenderMode 配置组件是否:

  • 在页面中预呈现。
  • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

可能需要额外的工作,具体取决于组件使用的静态资源以及布局页面在应用中的组织方式。 通常,脚本添加到了页面或视图的 Scripts 呈现部分,样式表添加到了布局的 <head> 元素内容。

使用 CSS 选择器,通过页面或视图呈现组件

配置解决方案(包括其他配置)后,将根组件添加到 Program.cs 中托管的 Blazor WebAssembly 解决方案的 Client 项目中。 下面的示例使用 CSS 选择器将 Counter 组件声明为根组件,该选择器会选择 idcounter-component 匹配的元素。 在下面的示例中,Client 项目的命名空间为 BlazorHosted.Client

Client 项目的 Program.cs 中,将项目的 Razor 组件的命名空间添加到文件顶部:

using BlazorHosted.Client.Pages;

Program.cs 中建立 builder 后,将 Counter 组件添加为根组件:

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

在下面的 Razor Pages 示例中,页面中呈现了 Counter 组件。 页面的呈现部分包含了 Blazor WebAssembly 脚本,以使组件成为交互式组件。

Server 项目中,Pages/RazorPagesCounter2.cshtml

@page

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

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

运行 Server 项目。 导航到 /razorpagescounter2 中的 Razor 页。 预呈现的 Counter 组件嵌入在页面中。

可能需要额外的工作,具体取决于组件使用的静态资源以及布局页面在应用中的组织方式。 通常,脚本添加到了页面或视图的 Scripts 呈现部分,样式表添加到了布局的 <head> 元素内容。

注意

如果 Blazor WebAssembly 应用已预呈现,并且使用 CSS 选择器同时集成到 Razor Pages 或 MVC 应用中,则前面的示例将引发 JSException。 导航到 Client 项目的 Razor 组件之一会引发以下异常:

Microsoft.JSInterop.JSException:找不到与选择器“#counter-component”匹配的任何元素。

这是正常行为,因为预呈现和集成具有可路由 Razor 组件的 Blazor WebAssembly 应用与使用 CSS 选择器不兼容。

Razor 组件可以集成到 Razor Pages 和 MVC 应用。 呈现页面或视图时,可以同时预呈现组件。

预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)

配置项目后,根据项目的要求按照下列部分中的指南操作:

Configuration

现有 Razor Pages 或 MVC 应用可以将 Razor 组件集成到页面和视图中:

  1. 在项目的布局文件中:

    • 将以下 <base> 标记添加到 Pages/Shared/_Layout.cshtml (Razor Pages) 或 Views/Shared/_Layout.cshtml (MVC) 中的 <head> 元素:

      <base href="~/" />
      

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

    • 在紧接着 Scripts 呈现部分的前方为 blazor.server.js 脚本添加 <script> 标记。

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

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

      框架会将 blazor.server.js 脚本添加到应用。 无需手动将 blazor.server.js 脚本文件添加到应用。

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

    _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. Startup.ConfigureServices 中注册 Blazor Server 服务。

    Startup.cs中:

    services.AddServerSideBlazor();
    
  4. 将 Blazor 中心终结点添加到 Startup.Configure 的终结点 (app.UseEndpoints)。

    Startup.cs:

    endpoints.MapBlazorHub();
    
  5. 将组件集成到任何页面或视图。 例如,将 Counter 组件添加到项目的 Shared 文件夹。

    Pages/Shared/Counter.razor (Razor Pages) 或 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:

    在 Razor Pages 应用的项目 Index 页中,添加 Counter 组件的命名空间,并将组件嵌入到页面中。 加载 Index 页面时,将在页面中预呈现 Counter 组件。 在下面的示例中,将 {APP 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>
    

    在上面的示例中,将 {APP NAMESPACE} 占位符替换为应用的命名空间。

    MVC:

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

    Views/Home/Index.cshtml:

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

有关详细信息,请参阅从页面或视图呈现组件部分。

在 Razor Pages 应用中使用可路由组件

本部分介绍如何添加可直接从用户请求路由的组件。

在 Razor Pages 应用中支持可路由 Razor 组件:

  1. 按照配置部分中的指南操作。

  2. 将具有以下内容的 App 组件添加到项目根。

    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>
    

    注意

    随着 ASP.NET Core 5.0.1 的发布及任何附加 5.x 版本的推出,Router 组件包含 PreferExactMatches 参数(设置为 @true)。 有关详细信息,请参阅从 ASP.NET Core 3.1 迁移到 5.0

  3. 将具有以下内容的 _Host 页面添加到项目。

    Pages/_Host.cshtml:

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

    组件将共享 _Layout.cshtml 文件用于布局。

    RenderMode 会配置 App 组件是否:

    • 在页面中预呈现。
    • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

    有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

  4. Startup.csStartup.Configure 终结点中,将 _Host 页面的低优先级路由添加为最后一个终结点:

    endpoints.MapFallbackToPage("/_Host");
    

    以下示例显示了典型应用的终结点配置中添加的行:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    
  5. 将可路由组件添加到项目。

    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. 运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。

有关命名空间的详细信息,请参阅组件命名空间部分。

在 MVC 应用中使用可路由组件

本部分介绍如何添加可直接从用户请求路由的组件。

在 MVC 应用中支持可路由 Razor 组件:

  1. 按照配置部分中的指南操作。

  2. 将具有以下内容的 App 组件添加到项目根。

    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>
    

    注意

    随着 ASP.NET Core 5.0.1 的发布及任何附加 5.x 版本的推出,Router 组件包含 PreferExactMatches 参数(设置为 @true)。 有关详细信息,请参阅从 ASP.NET Core 3.1 迁移到 5.0

  3. 将具有以下内容的 _Host 视图添加到项目。

    Views/Home/_Host.cshtml:

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

    组件将共享 _Layout.cshtml 文件用于布局。

    RenderMode 会配置 App 组件是否:

    • 在页面中预呈现。
    • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

    有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

  4. 向 Home 控制器添加操作。

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. Startup.csStartup.Configure 终结点中,添加返回 _Host 视图的控制器操作的低优先级路由:

    endpoints.MapFallbackToController("Blazor", "Home");
    

    以下示例显示了典型应用的终结点配置中添加的行:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToController("Blazor", "Home");
    });
    
  6. 将可路由组件添加到项目。

    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. 运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。

有关命名空间的详细信息,请参阅组件命名空间部分。

从页面或视图呈现组件

本部分介绍如何在无法从用户请求直接路由组件的情况下,将组件添加到页面或视图。

若要从页面或视图呈现组件,请使用组件标记帮助程序

呈现有状态交互式组件

可以将有状态的交互式组件添加到 Razor 页面或视图。

呈现页面或视图时:

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

以下 Razor 页面将呈现 Counter 组件:

<h1>My Razor Page</h1>

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

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

有关详细信息,请参阅 ASP.NET Core 中的组件标记帮助程序

呈现非交互式组件

在以下 Razor 页面中,使用以下格式通过指定的初始值静态呈现 Counter 组件。 由于该组件是以静态方式呈现的,因此它不是交互式组件:

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

有关详细信息,请参阅 ASP.NET Core 中的组件标记帮助程序

组件命名空间

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

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

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

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

其他 Blazor WebAssembly 资源

预呈现状态大小和 SignalR 消息大小限制

较大的预呈现状态大小可能会超出 SignalR 线路消息大小限制,从而导致以下结果:

  • SignalR 线路初始化失败,客户端上出现错误:Circuit host not initialized.
  • 当线路发生故障时,客户端上显示重新连接 UI。 无法进行恢复。

若要解决此问题,请使用以下任一方法

  • 减少要置于预呈现状态的数据量。
  • 增加 SignalR 消息大小限制。 警告:增加限制可能会增加拒绝服务 (DoS) 攻击风险

其他 Blazor Server 资源

.NET 5 或更高版本中的 ASP.NET Core 支持通过托管的 Blazor WebAssembly解决方案将 Razor 组件集成到 Razor Pages 和 MVC 应用。 请选择本文的 .NET 5 或更高版本。

Razor 组件可以集成到 Razor Pages 和 MVC 应用。 呈现页面或视图时,可以同时预呈现组件。

预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)

配置项目后,根据项目的要求按照下列部分中的指南操作:

Configuration

现有 Razor Pages 或 MVC 应用可以将 Razor 组件集成到页面和视图中:

  1. 在项目的布局文件中:

    • 将以下 <base> 标记添加到 Pages/Shared/_Layout.cshtml (Razor Pages) 或 Views/Shared/_Layout.cshtml (MVC) 中的 <head> 元素:

      + <base href="~/" />
      

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

    • 在紧接着 Scripts 呈现部分的前方为 blazor.server.js 脚本添加 <script> 标记。

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

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

      框架会将 blazor.server.js 脚本添加到应用。 无需手动将 blazor.server.js 脚本文件添加到应用。

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

    _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. Startup.ConfigureServices 中注册 Blazor Server 服务。

    Startup.cs:

    services.AddServerSideBlazor();
    
  4. 将 Blazor 中心终结点添加到 Startup.Configure 的终结点 (app.UseEndpoints)。

    Startup.cs:

    endpoints.MapBlazorHub();
    
  5. 将组件集成到任何页面或视图。 例如,将 Counter 组件添加到项目的 Shared 文件夹。

    Pages/Shared/Counter.razor (Razor Pages) 或 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:

    在 Razor Pages 应用的项目 Index 页中,添加 Counter 组件的命名空间,并将组件嵌入到页面中。 加载 Index 页面时,将在页面中预呈现 Counter 组件。 在下面的示例中,将 {APP 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>
    

    在上面的示例中,将 {APP NAMESPACE} 占位符替换为应用的命名空间。

    MVC:

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

    Views/Home/Index.cshtml:

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

有关详细信息,请参阅从页面或视图呈现组件部分。

在 Razor Pages 应用中使用可路由组件

本部分介绍如何添加可直接从用户请求路由的组件。

在 Razor Pages 应用中支持可路由 Razor 组件:

  1. 按照配置部分中的指南操作。

  2. 将具有以下内容的 App 组件添加到项目根。

    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. 将具有以下内容的 _Host 页面添加到项目。

    Pages/_Host.cshtml:

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

    组件将共享 _Layout.cshtml 文件用于布局。

    RenderMode 会配置 App 组件是否:

    • 在页面中预呈现。
    • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

    有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

  4. Startup.csStartup.Configure 终结点中,将 _Host 页面的低优先级路由添加为最后一个终结点:

    endpoints.MapFallbackToPage("/_Host");
    

    以下示例显示了典型应用的终结点配置中添加的行:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    
  5. 将可路由组件添加到项目。

    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. 运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。

有关命名空间的详细信息,请参阅组件命名空间部分。

在 MVC 应用中使用可路由组件

本部分介绍如何添加可直接从用户请求路由的组件。

在 MVC 应用中支持可路由 Razor 组件:

  1. 按照配置部分中的指南操作。

  2. 将具有以下内容的 App 组件添加到项目根。

    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. 将具有以下内容的 _Host 视图添加到项目。

    Views/Home/_Host.cshtml:

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

    组件将共享 _Layout.cshtml 文件用于布局。

    RenderMode 会配置 App 组件是否:

    • 在页面中预呈现。
    • 在页面上呈现为静态 HTML,或者包含从用户代理启动 Blazor 应用所需的信息。

    有关组件标记帮助程序的详细信息(包括传递参数和 RenderMode 配置),请参阅 ASP.NET Core 中的组件标记帮助程序

  4. 向 Home 控制器添加操作。

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. Startup.csStartup.Configure 终结点中,添加返回 _Host 视图的控制器操作的低优先级路由:

    endpoints.MapFallbackToController("Blazor", "Home");
    

    以下示例显示了典型应用的终结点配置中添加的行:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToController("Blazor", "Home");
    });
    
  6. 将可路由组件添加到项目。

    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. 运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。

有关命名空间的详细信息,请参阅组件命名空间部分。

从页面或视图呈现组件

本部分介绍如何在无法从用户请求直接路由组件的情况下,将组件添加到页面或视图。

若要从页面或视图呈现组件,请使用组件标记帮助程序

呈现有状态交互式组件

可以将有状态的交互式组件添加到 Razor 页面或视图。

呈现页面或视图时:

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

以下 Razor 页面将呈现 Counter 组件:

<h1>My Razor Page</h1>

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

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

有关详细信息,请参阅 ASP.NET Core 中的组件标记帮助程序

呈现非交互式组件

在以下 Razor 页面中,使用以下格式通过指定的初始值静态呈现 Counter 组件。 由于该组件是以静态方式呈现的,因此它不是交互式组件:

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

有关详细信息,请参阅 ASP.NET Core 中的组件标记帮助程序

组件命名空间

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

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

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

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

预呈现状态大小和 SignalR 消息大小限制

较大的预呈现状态大小可能会超出 SignalR 线路消息大小限制,从而导致以下结果:

  • SignalR 线路初始化失败,客户端上出现错误:Circuit host not initialized.
  • 当线路发生故障时,客户端上显示重新连接 UI。 无法进行恢复。

若要解决此问题,请使用以下任一方法

  • 减少要置于预呈现状态的数据量。
  • 增加 SignalR 消息大小限制。 警告:增加限制可能会增加拒绝服务 (DoS) 攻击风险

其他 Blazor Server 资源