将 ASP.NET 核心Razor组件与托管Blazor WebAssembly解决方案中的 MVC 或 Razor Pages 集成
注意
托管 Blazor WebAssembly 解决方案仍受支持,但项目模板已删除,在 .NET 8 或更高版本中不再受支持。 本文显示在最多 .NET 7 的目录中供参考,但请注意,.NET 7 是 不再受支持的标准支持术语 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。
本文介绍 Razor 托管 Blazor WebAssembly 应用的组件集成方案,包括预呈现 Razor 服务器上的组件。
重要
各 ASP.NET Core 版本中的框架更改导致本文提供了多组不同的说明。 在使用本文的指导之前,请确认本文顶部的文档版本选择器与要用于应用的 ASP.NET Core 版本匹配。
预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)。
解决方案配置
预呈现配置
若要设置托管 Blazor WebAssembly 应用的预呈现,请执行以下操作:
将 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
。- Visual Studio:在“其他信息”对话框中,创建 Blazor WebAssembly 应用时选中“托管的 ASP.NET Core”复选框。 在本文的示例中,该解决方案的名称为
从 Blazor WebAssemblyClient 项目中删除
wwwroot/index.html
文件。在 Client 项目中,删除
Program.cs
中的以下行:- builder.RootComponents.Add<App>("#app"); - builder.RootComponents.Add<HeadOutlet>("head::after");
将
_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 其他安全方案。
在 Server 项目的
Program.cs
文件中,将回退终结点从index.html
文件更改为_Host.cshtml
页面:删除:
- app.MapFallbackToFile("index.html");
添加:
app.MapFallbackToPage("/_Host");
如果 Client 和 Server 项目在预呈现期间使用一个或多个通用服务,则将服务注册分解为可以从这两个项目调用的方法。 有关详细信息,请参阅 ASP.NET Core Blazor 依赖项注入。
运行 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" />
导入的布局包含两个导航链接 Home
(Index
页)和 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
:
- © {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ © {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 图标文件。
警告
避免将静态资产放入 Client 和 Server 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
组件声明为根组件,该选择器会选择 id
与 counter-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
)导航到页面或视图。 页面或视图随嵌入式组件一起加载,而嵌入式组件按预期运行。
保留预呈现状态
在不保留预呈现状态的情况下,在预呈现期间使用的状态将丢失,并且在完全加载应用时必须重新创建。 如果任何状态都是异步设置的,则 UI 可能会闪烁,因为预呈现 UI 将替换为临时占位符,然后再次完全呈现。
要保留预呈现组件的状态,请使用“保留组件状态”标记帮助程序(参考源)。 在预呈现组件的应用的 _Host
页面的结束 </body>
标记内添加标记帮助程序的标记 <persist-component-state />
。
注意
指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)。
在Pages/_Host.cshtml
托管Blazor WebAssembly应用中,WebAssembly 预呈现 (WebAssemblyPrerendered
) 的应用:Blazor
<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 相匹配,因此浏览器不会闪烁。
持久预呈现状态将传输到客户端,用于还原组件状态。 对于托管 Blazor WebAssembly 应用中的预呈现,数据将公开给浏览器,并且不得包含敏感的私有信息。
其他 Blazor WebAssembly 资源
- 状态管理:处理预呈现
- 对程序集延迟加载的预呈现支持
- 与预呈现相关的 Razor 组件生命周期主题
- 组件初始化 (
OnInitialized{Async}
) - 组件呈现后 (
OnAfterRender{Async}
) - 预呈现后的有状态重新连接:尽管本部分中的内容重点介绍 Blazor Server 和有状态 SignalR 重新连接,但在托管的 Blazor WebAssembly 应用 (WebAssemblyPrerendered) 中预呈现的方案涉及相似的条件和防止执行两次开发人员代码的方法。 若要在预呈现时保留初始化代码执行期间的状态,请参阅本文的保留预呈现状态部分。
- 使用 JavaScript 互操作预呈现
- 组件初始化 (
- 与预呈现相关的身份验证和授权主题
- 托管和部署:Blazor WebAssembly
- 处理错误:预呈现
- 在预呈现时执行了 OnNavigateAsync 两次:使用
OnNavigateAsync
处理异步导航事件
预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)。
解决方案配置
预呈现配置
若要设置托管 Blazor WebAssembly 应用的预呈现,请执行以下操作:
将 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
。- Visual Studio:在“其他信息”对话框中,创建 Blazor WebAssembly 应用时选中“托管的 ASP.NET Core”复选框。 在本文的示例中,该解决方案的名称为
从 Blazor WebAssemblyClient 项目中删除
wwwroot/index.html
文件。在 Client 项目中,删除
Program.cs
中的以下行:- builder.RootComponents.Add<App>("#app"); - builder.RootComponents.Add<HeadOutlet>("head::after");
将
_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 其他安全方案。
在 Server 的
Program.cs
项目的终结点映射中,将回退从index.html
文件更改为_Host.cshtml
页面:删除:
- app.MapFallbackToFile("index.html");
添加:
app.MapFallbackToPage("/_Host");
如果 Client 和 Server 项目在预呈现期间使用一个或多个通用服务,则将服务注册分解为可以从这两个项目调用的方法。 有关详细信息,请参阅 ASP.NET Core Blazor 依赖项注入。
运行 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" />
导入的布局包含两个导航链接 Home
(Index
页)和 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
:
- © {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ © {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 图标文件。
警告
避免将静态资产放入 Client 和 Server 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
组件声明为根组件,该选择器会选择 id
与 counter-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
)导航到页面或视图。 页面或视图随嵌入式组件一起加载,而嵌入式组件按预期运行。
保留预呈现状态
在不保留预呈现状态的情况下,在预呈现期间使用的状态将丢失,并且在完全加载应用时必须重新创建。 如果任何状态都是异步设置的,则 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 相匹配,因此浏览器不会闪烁。
持久预呈现状态将传输到客户端,用于还原组件状态。 对于托管 Blazor WebAssembly 应用中的预呈现,数据将公开给浏览器,并且不得包含敏感的私有信息。
其他 Blazor WebAssembly 资源
- 状态管理:处理预呈现
- 对程序集延迟加载的预呈现支持
- 与预呈现相关的 Razor 组件生命周期主题
- 组件初始化 (
OnInitialized{Async}
) - 组件呈现后 (
OnAfterRender{Async}
) - 预呈现后的有状态重新连接:尽管本部分中的内容重点介绍 Blazor Server 和有状态 SignalR 重新连接,但在托管的 Blazor WebAssembly 应用 (WebAssemblyPrerendered) 中预呈现的方案涉及相似的条件和防止执行两次开发人员代码的方法。 若要在预呈现时保留初始化代码执行期间的状态,请参阅本文的保留预呈现状态部分。
- 使用 JavaScript 互操作预呈现
- 组件初始化 (
- 与预呈现相关的身份验证和授权主题
- 托管和部署:Blazor WebAssembly
预呈现通过呈现搜索引擎可用来计算网页排名的初始 HTTP 响应的内容,可以改进搜索引擎优化 (SEO)。
解决方案配置
预呈现配置
若要设置托管 Blazor WebAssembly 应用的预呈现,请执行以下操作:
将 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
。- Visual Studio:在“其他信息”对话框中,创建 Blazor WebAssembly 应用时选中“托管的 ASP.NET Core”复选框。 在本文的示例中,该解决方案的名称为
从 Blazor WebAssemblyClient 项目中删除
wwwroot/index.html
文件。在 Client 项目中,删除
Program.cs
中的以下行:- builder.RootComponents.Add<App>("#app");
将
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>
在 Server 项目的
Startup.Configure
中,将回退从index.html
文件更改为_Host.cshtml
页面。Startup.cs
:- endpoints.MapFallbackToFile("index.html"); + endpoints.MapFallbackToPage("/_Host");
如果 Client 和 Server 项目在预呈现期间使用一个或多个通用服务,则将服务注册分解为可以从这两个项目调用的方法。 有关详细信息,请参阅 ASP.NET Core Blazor 依赖项注入。
运行 Server 项目。 托管 Blazor WebAssembly 应用由客户端的 Server 项目预呈现。
用于将 Razor 组件嵌入页面或视图的配置
本文中的以下部分和示例,用于将客户端Blazor WebAssembly应用的组件嵌入Razor服务器应用的页面或视图需要其他配置。
使用 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>
导入的布局包含 Home
和 Privacy
导航链接。 若要使 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 图标文件。
警告
避免将静态资产放入 Client 和 Server 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
组件声明为根组件,该选择器会选择 id
与 counter-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 选择器不兼容。
其他 Blazor WebAssembly 资源
- 状态管理:处理预呈现
- 对程序集延迟加载的预呈现支持
- 与预呈现相关的 Razor 组件生命周期主题
- 组件初始化 (
OnInitialized{Async}
) - 组件呈现后 (
OnAfterRender{Async}
) - 预呈现后的有状态重新连接:尽管本部分中的内容重点介绍 Blazor Server 和有状态 SignalR 重新连接,但在托管的 Blazor WebAssembly 应用 (WebAssemblyPrerendered) 中预呈现的方案涉及相似的条件和防止执行两次开发人员代码的方法。 若要在预呈现时保留初始化代码执行期间的状态,请参阅本文的保留预呈现状态部分。
- 使用 JavaScript 互操作预呈现
- 组件初始化 (
- 与预呈现相关的身份验证和授权主题
- 托管和部署:Blazor WebAssembly
.NET 5 或更高版本的 ASP.NET Core 支持将 Razor 组件集成到 Razor 托管 Blazor WebAssembly解决方案 中的 Pages 或 MVC 应用中。 请选择本文的 .NET 5 或更高版本。