使用 ASP.NET Core 中的 Razor 类库项目创建可重用 UI
Razor 视图、页面、控制器、页面模型、Razor组件、视图组件和数据模型可以构建到 Razor 类库 (RCL) 中。 RCL 可以打包并重复使用。 应用程序可以包括 RCL,并重写其中包含的视图和页面。 如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。
有关如何将 npm 和 webpack 集成到 RCL 的生成过程的信息,请参阅为 Razor 类库生成客户端 Web 资产。
创建一个包含 Razor UI 的类库
- 在 Visual Studio 中,选择“创建新项目”。
- 选择“Razor 类库”>“下一步”。
- 命名该库(例如,“RazorClassLib”)>“创建”。 为避免与已生成的视图库发生文件名冲突,请确保库名称不以
.Views
结尾。 - 如果需要库包含页面和/或视图,请选择支持页面和视图。 默认情况下,仅支持 Razor 组件。 选择创建。
默认情况下,Razor 类库模板默认为 Razor 组件开发。 “支持页面和视图”选项支持页面和视图。 有关 Blazor 的 RCL 支持的详细信息,请参阅使用 Razor 类库 (RCL) 中的 ASP.NET Core Razor 组件。
将 Razor 文件添加到 RCL。
ASP.NET Core 模板假定 RCL 内容位于 Areas
文件夹中。 请参阅以下 RCL 页面布局,创建公开 ~/Pages
中内容(而非 ~/Areas/Pages
中内容)的 RCL。
引用 RCL 内容
可以通过以下方式引用 RCL:
- NuGet 包。 请参阅创建 NuGet 包、dotnet 添加包和创建和发布 NuGet 包。
{ProjectName}.csproj
。 请查看 dotnet-add 引用。
重写视图、分部视图和页面
如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。 例如,将 WebApp1/Areas/MyFeature/Pages/Page1.cshtml
添加到 WebApp1,则 WebApp1 中的 Page1 会优先于 RCL 中的 Page1。
在示例下载中,将 WebApp1/Areas/MyFeature2
重命名为 WebApp1/Areas/MyFeature
以测试优先级。
将 RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml
分部视图复制到 WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml
。 更新标记以指示新的位置。 生成并运行应用,验证使用部分的应用版本。
如果 RCL 使用 Razor Pages,请在托管应用中启用 Razor Pages 服务和终结点:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
RCL 页面布局
若要将 RCL 内容作为 Web 应用 Pages
文件夹的一部分引用,请使用以下文件结构创建 RCL 项目:
RazorUIClassLib/Pages
RazorUIClassLib/Pages/Shared
假设 RazorUIClassLib/Pages/Shared
包含两个分部文件:_Header.cshtml
和 _Footer.cshtml
。 可将 <partial>
标记添加到 _Layout.cshtml
文件:
<body>
<partial name="_Header">
@RenderBody()
<partial name="_Footer">
</body>
将 _ViewStart.cshtml
文件添加到 RCL 项目的 Pages
文件夹中,以使用主机 Web 应用中的 _Layout.cshtml
文件:
@{
Layout = "_Layout";
}
创建具有静态资产的 RCL
RCL 可能需要 RCL 或 RCL 的消耗应用可以引用的伴随静态资产。 ASP.NET Core 允许创建 RCL,这些 RCL 包括可供消耗应用使用的静态资产。
若要将伴随资产作为 RCL 的一部分包括在内,请在类库中创建 wwwroot
文件夹,并在该文件夹中包括所有必需的文件。
打包 RCL 时,wwwroot
文件夹中的所有伴随资产都会自动包括在包中。
使用 dotnet pack
命令,而不是 Nuget.exe 版本 nuget pack
。
将客户端 Web 资产添加到生成流程
将客户端 Web 资产集成到生成管道中非常重要。 有关详细信息,请参阅为 Razor 类库生成客户端 Web 资产。
排除静态资产
若要排除静态资产,请将所需的排除路径添加到项目文件中的 $(DefaultItemExcludes)
属性组。 使用分号 (;
) 分隔条目。
在以下示例中,wwwroot
文件夹中的 lib.css
样式表不被视为静态资产,并且不包括在已发布的 RCL 中:
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>
TypeScript 集成
若要在 RCL 中包括 TypeScript 文件,请执行以下操作:
在项目中引用
Microsoft.TypeScript.MSBuild
NuGet 包。注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
将 TypeScript 文件 (
.ts
) 置于wwwroot
文件夹之外。 例如,将文件置于Client
文件夹中。为
wwwroot
文件夹配置 TypeScript 生成输出。 在项目文件的PropertyGroup
内设置TypescriptOutDir
属性:<TypescriptOutDir>wwwroot</TypescriptOutDir>
通过在项目文件的
PropertyGroup
内添加以下目标,将 TypeScript 目标作为PrepareForBuildDependsOn
目标的依赖项包括在内:<PrepareForBuildDependsOn> CompileTypeScript; GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn) </PrepareForBuildDependsOn>
使用引用的 RCL 中的内容
RCL 的 wwwroot
文件夹中包括的文件使用前缀 _content/{PACKAGE ID}/
向 RCL 或消耗应用公开。 例如,程序集名称为 Razor.Class.Lib
且在其项目文件中未指定 <PackageId>
的库会生成指向 _content/Razor.Class.Lib/
处的静态内容的路径。 当生成 NuGet 包且程序集名称与包 ID 不同(库项目文件中的 <PackageId>
)时,使用项目文件中为 {PACKAGE ID}
指定的包 ID。
消耗应用使用 <script>
、<style>
、<img>
和其他 HTML 标记引用库提供的静态资产。 消耗应用必须在以下情况下启用静态文件支持:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
从生成输出 (dotnet run
) 运行消耗应用时,默认在开发环境中启用静态 Web 资产。 从生成输出运行时,若要在其他环境中支持资产,请在 Program.cs
中的主机生成器上调用 UseStaticWebAssets:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseWebRoot("wwwroot");
builder.WebHost.UseStaticWebAssets();
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
从已发布输出 (dotnet publish
) 运行应用时,无需调用 UseStaticWebAssets
。
多项目开发流程
消耗应用运行时:
- RCL 中的资产停留在其原始文件夹中。 资产不会移至消耗应用。
- 重新生成 RCL 后,RCL 的
wwwroot
文件夹中的所有更改都会反映在消耗应用中,而无需重新生成消耗应用。
生成 RCL 时,还会生成描述静态 Web 资产位置的清单。 消耗应用在运行时读取清单,以使用引用项目和包中的资产。 将新资产添加到 RCL 后,必须先重新生成 RCL 以更新其清单,然后消耗应用才能访问新资产。
发布
发布应用后,来自所有引用项目和包的伴随资产都会复制到已发布应用的 wwwroot
文件夹中的 _content/{PACKAGE ID}/
下。 生成 NuGet 包且程序集名称与包 ID 不同(库项目文件中的 <PackageId>
)时,使用项目文件中为 {PACKAGE ID}
指定的包 ID 来检查 wwwroot
文件夹中的已发布资产。
其他资源
Razor 视图、页面、控制器、页面模型、Razor组件、视图组件和数据模型可以构建到 Razor 类库 (RCL) 中。 RCL 可以打包并重复使用。 应用程序可以包括 RCL,并重写其中包含的视图和页面。 如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。
有关如何将 npm 和 webpack 集成到 Razor 类库的生成过程的信息,请参阅为 Razor 类库生成客户端 Web 资产。
创建一个包含 Razor UI 的类库
- 在 Visual Studio 中,选择“创建新项目”。
- 选择“Razor 类库”>“下一步”。
- 命名该库(例如,“RazorClassLib”)>“创建”。 为避免与已生成的视图库发生文件名冲突,请确保库名称不以
.Views
结尾。 - 如果需要支持视图,请选择“支持页面和视图”。 默认情况下,仅支持 Razor 页面。 选择“创建”。
默认情况下,Razor 类库 (RCL) 模板默认为 Razor 组件开发。 “支持页面和视图”选项支持页面和视图。
将 Razor 文件添加到 RCL。
ASP.NET Core 模板假定 RCL 内容位于 Areas
文件夹中。 请参阅以下 RCL 页面布局,创建公开 ~/Pages
中内容(而非 ~/Areas/Pages
中内容)的 RCL。
引用 RCL 内容
可以通过以下方式引用 RCL:
- NuGet 包。 请参阅创建 NuGet 包、dotnet 添加包和创建和发布 NuGet 包。
{ProjectName}.csproj
。 请查看 dotnet-add 引用。
重写视图、分部视图和页面
如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。 例如,将 WebApp1/Areas/MyFeature/Pages/Page1.cshtml
添加到 WebApp1,则 WebApp1 中的 Page1 会优先于 RCL 中的 Page1。
在示例下载中,将 WebApp1/Areas/MyFeature2
重命名为 WebApp1/Areas/MyFeature
以测试优先级。
将 RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml
分部视图复制到 WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml
。 更新标记以指示新的位置。 生成并运行应用,验证使用部分的应用版本。
如果 RCL 使用 Razor Pages,请在托管应用中启用 Razor Pages 服务和终结点:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
RCL 页面布局
若要将 RCL 内容作为 Web 应用 Pages
文件夹的一部分引用,请使用以下文件结构创建 RCL 项目:
RazorUIClassLib/Pages
RazorUIClassLib/Pages/Shared
假设 RazorUIClassLib/Pages/Shared
包含两个分部文件:_Header.cshtml
和 _Footer.cshtml
。 可将 <partial>
标记添加到 _Layout.cshtml
文件:
<body>
<partial name="_Header">
@RenderBody()
<partial name="_Footer">
</body>
将 _ViewStart.cshtml
文件添加到 RCL 项目的 Pages
文件夹中,以使用主机 Web 应用中的 _Layout.cshtml
文件:
@{
Layout = "_Layout";
}
创建具有静态资产的 RCL
RCL 可能需要 RCL 或 RCL 的消耗应用可以引用的伴随静态资产。 ASP.NET Core 允许创建 RCL,这些 RCL 包括可供消耗应用使用的静态资产。
若要将伴随资产作为 RCL 的一部分包括在内,请在类库中创建 wwwroot
文件夹,并在该文件夹中包括所有必需的文件。
打包 RCL 时,wwwroot
文件夹中的所有伴随资产都会自动包括在包中。
使用 dotnet pack
命令,而不是 Nuget.exe 版本 nuget pack
。
排除静态资产
若要排除静态资产,请将所需的排除路径添加到项目文件中的 $(DefaultItemExcludes)
属性组。 使用分号 (;
) 分隔条目。
在以下示例中,wwwroot
文件夹中的 lib.css
样式表不被视为静态资产,并且不包括在已发布的 RCL 中:
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>
TypeScript 集成
若要在 RCL 中包括 TypeScript 文件,请执行以下操作:
在项目中引用
Microsoft.TypeScript.MSBuild
NuGet 包。注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
将 TypeScript 文件 (
.ts
) 置于wwwroot
文件夹之外。 例如,将文件置于Client
文件夹中。为
wwwroot
文件夹配置 TypeScript 生成输出。 在项目文件的PropertyGroup
内设置TypescriptOutDir
属性:<TypescriptOutDir>wwwroot</TypescriptOutDir>
通过在项目文件的
PropertyGroup
内添加以下目标,将 TypeScript 目标作为PrepareForBuildDependsOn
目标的依赖项包括在内:<PrepareForBuildDependsOn> CompileTypeScript; GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn) </PrepareForBuildDependsOn>
使用引用的 RCL 中的内容
RCL 的 wwwroot
文件夹中包括的文件使用前缀 _content/{PACKAGE ID}/
向 RCL 或消耗应用公开。 例如,程序集名称为 Razor.Class.Lib
且在其项目文件中未指定 <PackageId>
的库会生成指向 _content/Razor.Class.Lib/
处的静态内容的路径。 当生成 NuGet 包且程序集名称与包 ID 不同(库项目文件中的 <PackageId>
)时,使用项目文件中为 {PACKAGE ID}
指定的包 ID。
消耗应用使用 <script>
、<style>
、<img>
和其他 HTML 标记引用库提供的静态资产。 消耗应用必须在以下情况下启用静态文件支持:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
从生成输出 (dotnet run
) 运行消耗应用时,默认在开发环境中启用静态 Web 资产。 从生成输出运行时,若要在其他环境中支持资产,请在 Program.cs
中的主机生成器上调用 UseStaticWebAssets:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseWebRoot("wwwroot").UseStaticWebAssets();
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
注:.NET 6 只需调用 builder.WebHost.UseWebRoot("wwwroot").UseStaticWebAssets
。 有关详细信息,请参阅此 GitHub 问题。
从已发布输出 (dotnet publish
) 运行应用时,无需调用 UseStaticWebAssets
。
多项目开发流程
消耗应用运行时:
- RCL 中的资产停留在其原始文件夹中。 资产不会移至消耗应用。
- 重新生成 RCL 后,RCL 的
wwwroot
文件夹中的所有更改都会反映在消耗应用中,而无需重新生成消耗应用。
生成 RCL 时,还会生成描述静态 Web 资产位置的清单。 消耗应用在运行时读取清单,以使用引用项目和包中的资产。 将新资产添加到 RCL 后,必须先重新生成 RCL 以更新其清单,然后消耗应用才能访问新资产。
发布
发布应用后,来自所有引用项目和包的伴随资产都会复制到已发布应用的 wwwroot
文件夹中的 _content/{PACKAGE ID}/
下。 生成 NuGet 包且程序集名称与包 ID 不同(库项目文件中的 <PackageId>
)时,使用项目文件中为 {PACKAGE ID}
指定的包 ID 来检查 wwwroot
文件夹中的已发布资产。
其他资源
Razor 视图、页面、控制器、页面模型、Razor组件、视图组件和数据模型可以构建到 Razor 类库 (RCL) 中。 RCL 可以打包并重复使用。 应用程序可以包括 RCL,并重写其中包含的视图和页面。 如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。
创建一个包含 Razor UI 的类库
- 在 Visual Studio 中,选择“创建新项目”。
- 选择“Razor 类库”>“下一步”。
- 命名该库(例如,“RazorClassLib”)>“创建”>“下一步”。 为避免与已生成的视图库发生文件名冲突,请确保库名称不以
.Views
结尾。 - 选择“目标框架”。 选中“☑ 支持页面和视图”以支持视图。 默认情况下,仅支持 Razor 组件。 选择“创建”。
默认情况下,Razor 类库 (RCL) 模板默认为 Razor 组件开发。 “支持页面和视图”选项支持页面和视图。
将 Razor 文件添加到 RCL。
ASP.NET Core 模板假定 RCL 内容位于 Areas
文件夹中。 请参阅 RCL 页面布局,创建公开 ~/Pages
中内容(而非 ~/Areas/Pages
中内容)的 RCL。
引用 RCL 内容
可以通过以下方式引用 RCL:
- NuGet 包。 请参阅创建 NuGet 包、dotnet 添加包和创建和发布 NuGet 包。
{ProjectName}.csproj
。 请查看 dotnet-add 引用。
重写视图、分部视图和页面
如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。 例如,将 WebApp1/Areas/MyFeature/Pages/Page1.cshtml
添加到 WebApp1,则 WebApp1 中的 Page1 会优先于 RCL 中的 Page1。
在示例下载中,将 WebApp1/Areas/MyFeature2
重命名为 WebApp1/Areas/MyFeature
以测试优先级。
将 RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml
分部视图复制到 WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml
。 更新标记以指示新的位置。 生成并运行应用,验证使用部分的应用版本。
RCL 页面布局
若要将 RCL 内容作为 Web 应用 Pages
文件夹的一部分引用,请使用以下文件结构创建 RCL 项目:
RazorUIClassLib/Pages
RazorUIClassLib/Pages/Shared
假设 RazorUIClassLib/Pages/Shared
包含两个分部文件:_Header.cshtml
和 _Footer.cshtml
。 可将 <partial>
标记添加到 _Layout.cshtml
文件:
<body>
<partial name="_Header">
@RenderBody()
<partial name="_Footer">
</body>
将 _ViewStart.cshtml
文件添加到 RCL 项目的 Pages
文件夹中,以使用主机 Web 应用中的 _Layout.cshtml
文件:
@{
Layout = "_Layout";
}
创建具有静态资产的 RCL
RCL 可能需要 RCL 或 RCL 的消耗应用可以引用的伴随静态资产。 ASP.NET Core 允许创建 RCL,这些 RCL 包括可供消耗应用使用的静态资产。
若要将伴随资产作为 RCL 的一部分包括在内,请在类库中创建 wwwroot
文件夹,并在该文件夹中包括所有必需的文件。
打包 RCL 时,wwwroot
文件夹中的所有伴随资产都会自动包括在包中。
使用 dotnet pack
命令,而不是 Nuget.exe 版本 nuget pack
。
排除静态资产
若要排除静态资产,请将所需的排除路径添加到项目文件中的 $(DefaultItemExcludes)
属性组。 使用分号 (;
) 分隔条目。
在以下示例中,wwwroot
文件夹中的 lib.css
样式表不被视为静态资产,并且不包括在已发布的 RCL 中:
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>
TypeScript 集成
若要在 RCL 中包括 TypeScript 文件,请执行以下操作:
在项目中引用
Microsoft.TypeScript.MSBuild
NuGet 包。注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
将 TypeScript 文件 (
.ts
) 置于wwwroot
文件夹之外。 例如,将文件置于Client
文件夹中。为
wwwroot
文件夹配置 TypeScript 生成输出。 在项目文件的PropertyGroup
内设置TypescriptOutDir
属性:<TypescriptOutDir>wwwroot</TypescriptOutDir>
通过在项目文件的
PropertyGroup
内添加以下目标,将 TypeScript 目标作为ResolveCurrentProjectStaticWebAssets
目标的依赖项包括在内:<ResolveCurrentProjectStaticWebAssetsInputsDependsOn> CompileTypeScript; $(ResolveCurrentProjectStaticWebAssetsInputs) </ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
使用引用的 RCL 中的内容
RCL 的 wwwroot
文件夹中包括的文件使用前缀 _content/{PACKAGE ID}/
向 RCL 或消耗应用公开。 例如,程序集名称为 Razor.Class.Lib
且在其项目文件中未指定 <PackageId>
的库会生成指向 _content/Razor.Class.Lib/
处的静态内容的路径。 当生成 NuGet 包且程序集名称与包 ID 不同(库项目文件中的 <PackageId>
)时,使用项目文件中为 {PACKAGE ID}
指定的包 ID。
消耗应用使用 <script>
、<style>
、<img>
和其他 HTML 标记引用库提供的静态资产。 消耗应用必须在 Startup.Configure
中启用静态文件支持:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseStaticFiles();
...
}
从生成输出 (dotnet run
) 运行消耗应用时,默认在开发环境中启用静态 Web 资产。 从生成输出运行时,若要在其他环境中支持资产,请在 Program.cs
中的主机生成器上调用 UseStaticWebAssets
:
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStaticWebAssets();
webBuilder.UseStartup<Startup>();
});
}
从已发布输出 (dotnet publish
) 运行应用时,无需调用 UseStaticWebAssets
。
多项目开发流程
消耗应用运行时:
- RCL 中的资产停留在其原始文件夹中。 资产不会移至消耗应用。
- 重新生成 RCL 后,RCL 的
wwwroot
文件夹中的所有更改都会反映在消耗应用中,而无需重新生成消耗应用。
生成 RCL 时,还会生成描述静态 Web 资产位置的清单。 消耗应用在运行时读取清单,以使用引用项目和包中的资产。 将新资产添加到 RCL 后,必须先重新生成 RCL 以更新其清单,然后消耗应用才能访问新资产。
发布
发布应用后,来自所有引用项目和包的伴随资产都会复制到已发布应用的 wwwroot
文件夹中的 _content/{PACKAGE ID}/
下。 生成 NuGet 包且程序集名称与包 ID 不同(库项目文件中的 <PackageId>
)时,使用项目文件中为 {PACKAGE ID}
指定的包 ID 来检查 wwwroot
文件夹中的已发布资产。
其他资源
Razor 视图、页面、控制器、页面模型、Razor组件、视图组件和数据模型可以构建到 Razor 类库 (RCL) 中。 RCL 可以打包并重复使用。 应用程序可以包括 RCL,并重写其中包含的视图和页面。 如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。
创建一个包含 Razor UI 的类库
- 从 Visual Studio“文件”菜单中选择“新建”>“项目”。
- 选择“ASP.NET Core Web 应用程序”。
- 命名该库(例如,“RazorClassLib”)>“确定”。 为避免与已生成的视图库发生文件名冲突,请确保库名称不以
.Views
结尾。 - 验证是否已选择 ASP.NET Core 2.1 或更高版本。
- 选择“Razor 类库”>“确定”。
RCL 具有以下项目文件:
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
将 Razor 文件添加到 RCL。
ASP.NET Core 模板假定 RCL 内容位于 Areas
文件夹中。 请参阅 RCL 页面布局,创建公开 ~/Pages
中内容(而非 ~/Areas/Pages
中内容)的 RCL。
引用 RCL 内容
可以通过以下方式引用 RCL:
- NuGet 包。 请参阅创建 NuGet 包、dotnet 添加包和创建和发布 NuGet 包。
{ProjectName}.csproj
。 请查看 dotnet-add 引用。
演练:创建 RCL 项目并通过 Razor 页面项目使用
可以下载并测试完整项目,无需创建项目。 示例下载包含附加代码和链接,以方便测试项目。 可以在此 GitHub 问题中留下反馈,评论下载示例和分步说明的对比。
测试下载应用
如果尚未下载已完成的应用,并更愿意创建演练项目,请跳转至下一节。
在 Visual Studio 中打开 .sln
文件。 运行应用。
按“测试 Test WebApp1”中的说明进行操作
创建 RCL
本部分会创建 RCL。 将 Razor 文件添加到 RCL。
创建 RCL 项目:
- 从 Visual Studio“文件”菜单中选择“新建”>“项目”。
- 选择“ASP.NET Core Web 应用程序”。
- 将应用命名为 RazorUIClassLib>“确定”。
- 验证是否已选择 ASP.NET Core 2.1 或更高版本。
- 选择“Razor 类库”>“确定”。
- 添加一个名为
RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml
的 Razor 分部视图文件。
将 Razor 文件和文件夹添加到项目
使用以下代码替换
RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml
中的标记:<h3>_Message.cshtml partial view.</h3> <p>RazorUIClassLib\Areas\MyFeature\Pages\Shared\_Message.cshtml</p>
使用以下代码替换
RazorUIClassLib/Areas/MyFeature/Pages/Page1.cshtml
中的标记:@page @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <h2>Hello from a Razor UI class library!</h2> <p> From RazorUIClassLib\Areas\MyFeature\Pages\Page1.cshtml</p> <partial name="_Message" />
使用分步视图 (
<partial name="_Message" />
) 需要@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
。 可以添加一个_ViewImports.cshtml
文件,无需包含@addTagHelper
指令。 例如:dotnet new viewimports -o RazorUIClassLib/Areas/MyFeature/Pages
有关
_ViewImports.cshtml
的详细信息,请参阅导入共享指令生成类库以验证是否不存在编译器错误:
dotnet build RazorUIClassLib
生成输出包含 RazorUIClassLib.dll
和 RazorUIClassLib.Views.dll
。 RazorUIClassLib.Views.dll
包含已编译的 Razor 内容。
从 Razor 页面项目使用 Razor UI 库
创建 Razor 页面 Web 应用:
在解决方案资源管理器中,右键单击解决方案 >“添加”>“新建项目”。
选择“ASP.NET Core Web 应用程序”。
将应用命名为 WebApp1。
验证是否已选择 ASP.NET Core 2.1 或更高版本。
选择“Web 应用程序”>“确定”。
在解决方案资源管理器中,右键单击“WebApp1”,然后选择“设为启动项目” 。
在解决方案资源管理器中,右键单击“WebApp1”,然后选择“生成依赖项”>“项目依赖项”。
将 RazorUIClassLib 勾选为 WebApp1 的依赖项。
在解决方案资源管理器中,右键单击“WebApp1”,选择“添加”>“引用”。
在“引用管理器”对话框中勾选“RazorUIClassLib”>“确定”。
运行应用。
测试 WebApp1
浏览到 /MyFeature/Page1
以验证是否正在使用 Razor UI 类库。
重写视图、分部视图和页面
如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。 例如,将 WebApp1/Areas/MyFeature/Pages/Page1.cshtml
添加到 WebApp1,则 WebApp1 中的 Page1 会优先于 RCL 中的 Page1。
在示例下载中,将 WebApp1/Areas/MyFeature2
重命名为 WebApp1/Areas/MyFeature
以测试优先级。
将 RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml
分部视图复制到 WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml
。 更新标记以指示新的位置。 生成并运行应用,验证使用部分的应用版本。
RCL 页面布局
若要将 RCL 内容作为 Web 应用 Pages
文件夹的一部分引用,请使用以下文件结构创建 RCL 项目:
RazorUIClassLib/Pages
RazorUIClassLib/Pages/Shared
假设 RazorUIClassLib/Pages/Shared
包含两个分部文件:_Header.cshtml
和 _Footer.cshtml
。 可将 <partial>
标记添加到 _Layout.cshtml
文件:
<body>
<partial name="_Header">
@RenderBody()
<partial name="_Footer">
</body>
Razor 视图、页面、控制器、页面模型、Razor组件、视图组件和数据模型可以构建到 Razor 类库 (RCL) 中。 RCL 可以打包并重复使用。 应用程序可以包括 RCL,并重写其中包含的视图和页面。 如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。
创建一个包含 Razor UI 的类库
- 在 Visual Studio 中,选择“创建新项目”。
- 选择“Razor 类库”>“下一步”。
- 命名该库(例如,“RazorClassLib”)>“创建”。 为避免与已生成的视图库发生文件名冲突,请确保库名称不以
.Views
结尾。 - 如果需要支持视图,请选择“支持页面和视图”。 默认情况下,仅支持 Razor 页面。 选择“创建”。
默认情况下,Razor 类库 (RCL) 模板默认为 Razor 组件开发。 “支持页面和视图”选项支持页面和视图。
将 Razor 文件添加到 RCL。
ASP.NET Core 模板假定 RCL 内容位于 Areas
文件夹中。 请参阅以下 RCL 页面布局,创建公开 ~/Pages
中内容(而非 ~/Areas/Pages
中内容)的 RCL。
引用 RCL 内容
可以通过以下方式引用 RCL:
- NuGet 包。 请参阅创建 NuGet 包、dotnet 添加包和创建和发布 NuGet 包。
{ProjectName}.csproj
。 请查看 dotnet-add 引用。
重写视图、分部视图和页面
如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml
文件)优先。 例如,将 WebApp1/Areas/MyFeature/Pages/Page1.cshtml
添加到 WebApp1,则 WebApp1 中的 Page1 会优先于 RCL 中的 Page1。
在示例下载中,将 WebApp1/Areas/MyFeature2
重命名为 WebApp1/Areas/MyFeature
以测试优先级。
将 RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml
分部视图复制到 WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml
。 更新标记以指示新的位置。 生成并运行应用,验证使用部分的应用版本。
如果 RCL 使用 Razor Pages,请在托管应用中启用 Razor Pages 服务和终结点:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
RCL 页面布局
若要将 RCL 内容作为 Web 应用 Pages
文件夹的一部分引用,请使用以下文件结构创建 RCL 项目:
RazorUIClassLib/Pages
RazorUIClassLib/Pages/Shared
假设 RazorUIClassLib/Pages/Shared
包含两个分部文件:_Header.cshtml
和 _Footer.cshtml
。 可将 <partial>
标记添加到 _Layout.cshtml
文件:
<body>
<partial name="_Header">
@RenderBody()
<partial name="_Footer">
</body>
将 _ViewStart.cshtml
文件添加到 RCL 项目的 Pages
文件夹中,以使用主机 Web 应用中的 _Layout.cshtml
文件:
@{
Layout = "_Layout";
}
创建具有静态资产的 RCL
RCL 可能需要 RCL 或 RCL 的消耗应用可以引用的伴随静态资产。 ASP.NET Core 允许创建 RCL,这些 RCL 包括可供消耗应用使用的静态资产。
若要将伴随资产作为 RCL 的一部分包括在内,请在类库中创建 wwwroot
文件夹,并在该文件夹中包括所有必需的文件。
打包 RCL 时,wwwroot
文件夹中的所有伴随资产都会自动包括在包中。
使用 dotnet pack
命令,而不是 Nuget.exe 版本 nuget pack
。
排除静态资产
若要排除静态资产,请将所需的排除路径添加到项目文件中的 $(DefaultItemExcludes)
属性组。 使用分号 (;
) 分隔条目。
在以下示例中,wwwroot
文件夹中的 lib.css
样式表不被视为静态资产,并且不包括在已发布的 RCL 中:
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>
TypeScript 集成
若要在 RCL 中包括 TypeScript 文件,请执行以下操作:
在项目中引用
Microsoft.TypeScript.MSBuild
NuGet 包。注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
将 TypeScript 文件 (
.ts
) 置于wwwroot
文件夹之外。 例如,将文件置于Client
文件夹中。为
wwwroot
文件夹配置 TypeScript 生成输出。 在项目文件的PropertyGroup
内设置TypescriptOutDir
属性:<TypescriptOutDir>wwwroot</TypescriptOutDir>
通过在项目文件的
PropertyGroup
内添加以下目标,将 TypeScript 目标作为ResolveCurrentProjectStaticWebAssets
目标的依赖项包括在内:<ResolveCurrentProjectStaticWebAssetsInputsDependsOn> CompileTypeScript; $(ResolveCurrentProjectStaticWebAssetsInputs) </ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
使用引用的 RCL 中的内容
RCL 的 wwwroot
文件夹中包括的文件使用前缀 _content/{PACKAGE ID}/
向 RCL 或消耗应用公开。 例如,程序集名称为 Razor.Class.Lib
且在其项目文件中未指定 <PackageId>
的库会生成指向 _content/Razor.Class.Lib/
处的静态内容的路径。 当生成 NuGet 包且程序集名称与包 ID 不同(库项目文件中的 <PackageId>
)时,使用项目文件中为 {PACKAGE ID}
指定的包 ID。
消耗应用使用 <script>
、<style>
、<img>
和其他 HTML 标记引用库提供的静态资产。 消耗应用必须在 Startup.Configure
中启用静态文件支持:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseStaticFiles();
...
}
从生成输出 (dotnet run
) 运行消耗应用时,默认在开发环境中启用静态 Web 资产。 从生成输出运行时,若要在其他环境中支持资产,请在 Program.cs
中的主机生成器上调用 UseStaticWebAssets
:
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStaticWebAssets();
webBuilder.UseStartup<Startup>();
});
}
从已发布输出 (dotnet publish
) 运行应用时,无需调用 UseStaticWebAssets
。
多项目开发流程
消耗应用运行时:
- RCL 中的资产停留在其原始文件夹中。 资产不会移至消耗应用。
- 重新生成 RCL 后,RCL 的
wwwroot
文件夹中的所有更改都会反映在消耗应用中,而无需重新生成消耗应用。
生成 RCL 时,还会生成描述静态 Web 资产位置的清单。 消耗应用在运行时读取清单,以使用引用项目和包中的资产。 将新资产添加到 RCL 后,必须先重新生成 RCL 以更新其清单,然后消耗应用才能访问新资产。
发布
发布应用后,来自所有引用项目和包的伴随资产都会复制到已发布应用的 wwwroot
文件夹中的 _content/{PACKAGE ID}/
下。 生成 NuGet 包且程序集名称与包 ID 不同(库项目文件中的 <PackageId>
)时,使用项目文件中为 {PACKAGE ID}
指定的包 ID 来检查 wwwroot
文件夹中的已发布资产。