Razor类库
组件可以通过 Razor 类库(Razor Class Library, RCL)实现跨项目复用。Razor 类库不仅能够包含可重用的组件,还可以打包静态资源(如 CSS 和 JavaScript 文件)。由于这些组件本质上都是常规的 .NET 类型,因此通过 RCL 分发的组件最终会被编译为标准 .NET 程序集,这使得它们能够像其他类库一样被项目直接引用和使用。
一、使用Razor类库
创建Razor类库
在Blazor项目解决方案中,新建项目,选择Razor类库,创建一个名为ComponentLibrary的Razor类库。
引入Razor类库
在Blazor项目中,引用刚才创建的Razor类库。
在Blazor项目的_Imports.razor
文件中,应用命名控件,当然,如果不嫌麻烦,也可以在每个使用Razor类库的组件中单独引用。
使用组件
-
RazorRCLTest.razor
csharp@page "/razor-rcl" <h3>RazorRCLTest</h3> <Component1/> @code { }

二、其他设置
1、Razor类库中的可路由组件
如果要让Blazor项目中所引用的Razor类库中的可路由组件可以直接在浏览器中请求访问,则必须在相应的路由器公开该程序集。
-
以BlazorAuto Server为例,需要在
Program.cs
中,通过AddAdditionalAssemblies()
方法,将程序集加载到路由器中;然后在Route
组件上设置AdditionalAssemblies
属性。 -
详情可以参考跨程序集路由
-
Program.cs
csharp...... app.MapRazorComponents<App>() .AddInteractiveServerRenderMode() .AddAdditionalAssemblies(typeof(ComponentLibrary.ExampleJsInterop).Assembly); ......
-
Routes.razor
csharp<Router AppAssembly="..." AdditionalAssemblies="new[] { typeof(ComponentLibrary.ExampleJsInterop).Assembly }"> ... </Router>
2、应用静态资源
Razor类库中的静态资产(wwwroot
文件夹下的静态资源)可用于任何使用该库的应用。
访问路径
如果想在引用Razor类库的应用中使用类库中的静态资产,其访问路径为:_content/{PACKAGE ID}/{PATH AND FILE NAME}
{PACKAGE ID}
:Razor类库的PackageID,如果没有指定,则默认使用程序集名称。{PATH AND FILE NAME}
:wwwroot
下的路径和文件名。- 需要注意的是,在Razor类库自己的组件中也是通过这个路径进行静态资源的访问。
使用
将照片放入到Razor类库的wwwroot
下:

在Razor类库中创建JeepYJ.razor组件
-
JeepYJ.razor
csharp<h3>ComponentLibrary.JeepYJ</h3> <p> <img alt="Jeep YJ®" src="_content/ComponentLibrary/jeep-yj.png"/> </p>
在引用Razor类库的Blazor项目中创建Jeep.razor组件
-
Jeep.razor
csharp@page "/jeep" @using ComponentLibrary <div style="float:left;margin-right:10px"> <h3>Direct use</h3> <p> <img alt="Jeep YJ®" src="_content/ComponentLibrary/jeep-yj.png" /> </p> </div> <JeepYJ /> <p> <em>Jeep</em> and <em>Jeep YJ</em> are registered trademarks of <a href="https://www.stellantis.com">FCA US LLC (Stellantis NV)</a>. </p>

3、应用样式
关于CSS样式的引用,如果是作为样式文件放在wwwroot
下,那么在App.razor组件中使用_content/{PACKAGE ID}/{PATH AND FILE NAME}
路径进行引用即可。
关于组件库中的CSS隔离样式,并不需要进行而外的设置。
静态SSR
静态 SSR 是指组件在服务器处理传入 HTTP 请求时运行的模式。 Blazor 将组件渲染为 HTML,并包含在响应中。 发送响应后,将丢弃服务器端组件和渲染器状态,因此浏览器中只剩下 HTML。
这种模式的好处是托管成本更低且更具可缩放性,因为不需要持续的服务器资源来保存组件状态,浏览器和服务器之间不需要维护持续的连接,并且浏览器中不需要 WebAssembly 负载。
默认情况下,所有现有组件仍可与静态 SSR 一起使用。 然而,这种模式的代价是,由于以下原因,无法运行事件处理程序(例如@onclick
):
- 浏览器中没有 .NET 代码来运行它们。
- 服务器已直接丢弃执行事件处理程序或重新渲染相同组件实例所需的任何组件和渲染器状态。
这相当于在启动 Blazor 线路或 Blazor WebAssembly 运行时之前,组件在预渲染期间的行为方式
需要注意的是,表单的 @onsubmit
事件较为特殊,无论渲染模式如何,它始终正常运行。
如果组件的唯一作用只是生成只读的DOM内容,那么使用静态SSR就足够了。
何时使用 @rendermode
指令
在大多数情况下,创建组件时候不应该指定渲染模式,即使需要交互性也是如此。 这是因为我们不知道调用组件的应用是否支持组件中所指定的渲染模式,因此不应该在组件库的组件中直接使用@rendermode
指定渲染模式,使用什么渲染模式应该交给组件的调用者来决定。
使用 @rendermode
指令的唯一原因是该实现从根本上与一种特定渲染模式耦合,并且如果在其他模式下使用,肯定会导致错误。例如,一个组件其核心用途是使用 Windows 或特定于 Linux 的 API 直接与主机操作系统交互。 可能无法在 WebAssembly 上使用此类组件。 如果是这样,则应该为组件声明 @rendermode InteractiveServer
。
流式渲染
Razor类库中的组件可以自由地声明 @attribute [StreamRendering]
,用于流渲染([StreamRendering]
属性 API)。组件在所有情况下都可以正常运行。 即使在服务器上禁止静态 SSR 的流式处理,组件仍然可以渲染其正确的最终状态。
跨渲染使用链接
Razor类库中的组件可以使用链接和增强的导航。 无论是否有交互式 Router
组件,也无论是否在 DOM 的上级级别启用/禁用增强型导航,HTML <a>
标记都应产生等效的行为。
跨渲染使用表单
Razor类库中的组件可能会用到表单(<form>
或 <EditForm>
),表单组件可以在静态和交互式渲染模式下实现等效工作。
如下例中,Enhance
、FormName
和 SupplyParameterFromFormAttribute
API 仅在静态 SSR 期间使用,在交互式渲染期间会被忽略。 表单在交互式和静态 SSR 期间都正常工作。
-
示例
csharp<EditForm Enhance FormName="NewProduct" Model="Model" OnValidSubmit="SaveProduct"> <DataAnnotationsValidator /> <ValidationSummary /> <p>Name: <InputText @bind-Value="Item.Name" /></p> <button type="submit">Submit</button> </EditForm> @code { [SupplyParameterFromForm] public Product? Model { get; set; } protected override void OnInitialized() => Model ??= new(); private async Task Save() { ... } }
避免特定于静态 SSR 的 API
要创建适用于任何渲染模式的组件,请勿依赖 HttpContext
,因为它仅在静态 SSR 期间可用。 在交互式渲染期间使用 HttpContext
API 没有意义,因为这些时候没有活动的 HTTP 请求,考虑设置状态码或写入响应没有意义。
组件可在可用时自由接收HttpContext
,如下所示,该值在交互式渲染期间为 null
,并且仅在静态 SSR 期间进行设置。
csharp
[CascadingParameter]
public HttpContext? Context { get; set; }
注意,在许多情况下,有比使用 HttpContext
更好的替代方法。 如果需要知道当前 URL 或执行重定向,NavigationManager
上的 API 适用于所有渲染模式。 如果需要了解用户的身份验证状态,可以使用 Blazor 的 AuthenticationStateProvider
服务,而不是使用 HttpContext.User
。