隐藏

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

发布:2023/1/20 9:50:02作者:管理员 来源:本站 浏览次数:299

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


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


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


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


针对可直接通过用户请求进行路由的组件。 如果访问者应该能够使用 @page 指令在浏览器中为组件发出 HTTP 请求,则按照此指南操作。

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

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

有关不可直接通过用户请求进行路由的组件,请参阅通过页面或视图呈现组件部分。 如果应用使用组件标记帮助程序将组件嵌入到现有页面和视图,则按照此指南操作。

Configuration

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


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


_Imports.razor:


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}

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


将以下 <base> 标记和 HeadOutlet 组件标记帮助程序添加到 <head> 元素:


CSHTML


复制

<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> 标记:


HTML


复制

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

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


备注


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


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


C#


复制

builder.Services.AddServerSideBlazor();

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


C#


复制

app.MapBlazorHub();

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


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


razor


复制

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


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:


CSHTML


复制

@using {APP NAMESPACE}.Views.Shared

@{

   ViewData["Title"] = "Home Page";

}


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

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


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

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


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


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


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


App.razor:


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>

将具有以下内容的 _Host 页面添加到项目。 使用应用的命名空间替换 {APP NAMESPACE} 占位符。


Pages/_Host.cshtml:


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 中的组件标记帮助程序。


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


C#


复制

app.MapFallbackToPage("/_Host");

将可路由组件添加到项目。 以下示例是 RoutableCounter 组件,它基于 Blazor 项目模板中的 Counter 组件。


Pages/RoutableCounter.razor:


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

   }

}

运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。


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


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

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


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


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


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


App.razor:


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>

将具有以下内容的 _Host 视图添加到项目。 使用应用的命名空间替换 {APP NAMESPACE} 占位符。


Views/Home/_Host.cshtml:


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 中的组件标记帮助程序。


向 Home 控制器添加操作。


Controllers/HomeController.cs:


C#


复制

public IActionResult Blazor()

{

  return View("_Host");

}

在 Program.cs 终结点中,为返回 _Host 视图的控制器操作添加一个低优先级路由:


C#


复制

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

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


Pages/RoutableCounter.razor:


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

   }

}

运行项目并导航到 /routable-counter 中的可路由 RoutableCounter 组件。


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


从页面或视图呈现组件

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


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


呈现有状态交互式组件

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


呈现页面或视图时:


该组件通过页面或视图预呈现。

用于预呈现的初始组件状态丢失。

建立 SignalR 连接时,将创建新的组件状态。

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


CSHTML


复制

<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 组件。 由于该组件是以静态方式呈现的,因此它不是交互式组件:


CSHTML


复制

<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 表示文件夹的名称。

CSHTML


复制

@using {APP NAMESPACE}.Components

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


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


保留预呈现状态

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


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


Pages/_Host.cshtml:


CSHTML


复制

<body>

   ...


   <persist-component-state />

</body>

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


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


Pages/WeatherForecastPreserveState.razor:


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(DateOnly.FromDateTime(DateTime.Now));

       }

       else

       {

           forecasts = restored!;

       }

   }


   private Task PersistForecasts()

   {

       ApplicationState.PersistAsJson("fetchdata", forecasts);


       return Task.CompletedTask;

   }


   void IDisposable.Dispose()

   {

       persistingSubscription.Dispose();

   }

}

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


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

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


SignalR 线路初始化失败,客户端上出现错误:Circuit host not initialized.

当线路发生故障时,客户端上显示重新连接对话框。 无法进行恢复。

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


减少要置于预呈现状态的数据量。

增加 SignalR 消息大小限制。 警告:增加限制可能会增加拒绝服务 (DoS) 攻击风险。

其他 Blazor Server 资源

状态管理:处理预呈现

与预呈现相关的 Razor 组件生命周期主题

组件初始化 (OnInitialized{Async})

组件呈现后 (OnAfterRender{Async})

预呈现后的有状态重新连接

使用 JavaScript 互操作预呈现

身份验证和授权:一般方面

处理错误:Blazor Server 预呈现

托管和部署:Blazor Server

威胁缓解:跨站点脚本 (XSS)

建议的内容

ASP.NET Core Blazor 项目结构

了解 ASP.NET Core Blazor 应用项目结构。

ASP.NET Core Blazor 布局

了解如何为 Blazor 应用创建可重用布局组件。

ASP.NET Core Blazor 启动

了解如何配置 Blazor 启动。

在 ASP.NET Core 应用中控制 Blazorhead 内容

了解如何在 应用中控制 Blazorhead 内容,包括如何从组件设置页标题。

ASP.NET Core Razor 组件

了解如何在 Blazor 应用中创建和使用 Razor 组件,包括有关 Razor 语法、组件命名、命名空间和组件参数的指导。

ASP.NET Core Blazor 基础知识

了解 Blazor 应用程序框架的基础概念。

动态呈现的 ASP.NET Core Razor 组件

了解如何在 Blazor 应用中使用动态呈现的组件 Razor。

ASP.NET Core Blazor 状态管理

了解如何在 Blazor 应用中保留用户数据(状态)。

本文内容


Configuration

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

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

从页面或视图呈现组件