在 ASP.NET Core 中使用 Razor 类库项目创建可重用的 UICreate reusable UI using the Razor class library project in ASP.NET Core

作者:Rick AndersonBy Rick Anderson

Razor 视图、页、控制器、页模型、 razor 组件视图组件和数据模型可以内置于 Razor 类库(RCL)中。Razor views, pages, controllers, page models, Razor components, View components, and data models can be built into a Razor class library (RCL). RCL 可以打包并重复使用。The RCL can be packaged and reused. 应用程序可以包括 RCL,并重写其中包含的视图和页面。Applications can include the RCL and override the views and pages it contains. 如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml 文件)优先。When a view, partial view, or Razor Page is found in both the web app and the RCL, the Razor markup (.cshtml file) in the web app takes precedence.

查看或下载示例代码如何下载View or download sample code (how to download)

创建一个包含 Razor UI 的类库Create a class library containing Razor UI

  • 从 Visual Studio 中选择 "新建项目"。From Visual Studio select Create new a new project.
  • 选择 " Razor 类库>"下一步"。Select Razor Class Library > Next.
  • 命名库(例如 "RazorClassLib"),>创建Name the library (for example, "RazorClassLib"), > Create. 为避免与已生成的视图库发生文件名冲突,请确保库名称不以 .Views 结尾。To avoid a file name collision with the generated view library, ensure the library name doesn't end in .Views.
  • 如果需要支持视图,请选择 "支持页和视图"。Select Support pages and views if you need to support views. 默认情况下,仅支持 Razor Pages。By default, only Razor Pages are supported. 选择“创建”。Select Create.

默认情况下,Razor 类库 (RCL) 模板默认为 Razor 组件开发。The Razor class library (RCL) template defaults to Razor component development by default. 支持页和视图选项支持页和视图。The Support pages and views option supports pages and views.

将 Razor 文件添加到 RCL。Add Razor files to the RCL.

ASP.NET Core 模板假设 RCL 内容位于 "区域" 文件夹中。The ASP.NET Core templates assume the RCL content is in the Areas folder. 请参阅RCL Pages layout ,以创建 RCL,以在 ~/Pages 而不是 ~/Areas/Pages公开内容。See RCL Pages layout to create an RCL that exposes content in ~/Pages rather than ~/Areas/Pages.

引用 RCL 内容Reference RCL content

可以通过以下方式引用 RCL:The RCL can be referenced by:

重写视图、分部视图和页面Override views, partial views, and pages

如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml 文件)优先。When a view, partial view, or Razor Page is found in both the web app and the RCL, the Razor markup (.cshtml file) in the web app takes precedence. 例如,将WebApp1/Areas/MyFeature/Pages/Page1. cshtml添加到 WebApp1,WebApp1 中的 page1 将优先于 RCL 中的 page1。For example, add WebApp1/Areas/MyFeature/Pages/Page1.cshtml to WebApp1, and Page1 in the WebApp1 will take precedence over Page1 in the RCL.

在示例下载中,将 WebApp1/Areas/MyFeature2 重命名为 WebApp1/Areas/MyFeature 来测试优先级。In the sample download, rename WebApp1/Areas/MyFeature2 to WebApp1/Areas/MyFeature to test precedence.

将 RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml 分部视图复制到 WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml。Copy the RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml partial view to WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. 更新标记以指示新的位置。Update the markup to indicate the new location. 生成并运行应用,验证使用部分的应用版本。Build and run the app to verify the app's version of the partial is being used.

RCL 页面布局RCL Pages layout

若要引用 RCL 内容(如同它是 web 应用的Pages文件夹的一部分),请创建具有以下文件结构的 RCL 项目:To reference RCL content as though it is part of the web app's Pages folder, create the RCL project with the following file structure:

  • RazorUIClassLib/PagesRazorUIClassLib/Pages
  • RazorUIClassLib/Pages/SharedRazorUIClassLib/Pages/Shared

假设RazorUIClassLib/Pages/Shared包含两部分文件: _Header_FooterSuppose RazorUIClassLib/Pages/Shared contains two partial files: _Header.cshtml and _Footer.cshtml. 可以将 <partial> 标记添加到 _Layout文件中:The <partial> tags could be added to _Layout.cshtml file:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

使用静态资产创建 RCLCreate an RCL with static assets

RCL 可能需要随附静态资产,这些资产可由 RCL 的使用应用程序引用。An RCL may require companion static assets that can be referenced by the consuming app of the RCL. ASP.NET Core 允许创建包含可用于使用中的应用的静态资产的 RCLs。ASP.NET Core allows creating RCLs that include static assets that are available to a consuming app.

若要将配套资产作为 RCL 的一部分包括在内,请在类库中创建wwwroot文件夹,并在该文件夹中包含所有必需的文件。To include companion assets as part of an RCL, create a wwwroot folder in the class library and include any required files in that folder.

当对 RCL 进行打包时, wwwroot文件夹中的所有伴随资产将自动包含在包中。When packing an RCL, all companion assets in the wwwroot folder are automatically included in the package.

排除静态资产Exclude static assets

若要排除静态资产,请将所需的排除路径添加到项目文件中的 $(DefaultItemExcludes) 属性组。To exclude static assets, add the desired exclusion path to the $(DefaultItemExcludes) property group in the project file. 用分号(;)分隔条目。Separate entries with a semicolon (;).

在下面的示例中, wwwroot文件夹中的lib样式表不被视为静态资产,而且不包含在已发布的 RCL 中:In the following example, the lib.css stylesheet in the wwwroot folder isn't considered a static asset and isn't included in the published RCL:

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Typescript 集成Typescript integration

若要在 RCL 中包含 TypeScript 文件:To include TypeScript files in an RCL:

  1. 将 TypeScript 文件(ts)置于wwwroot文件夹之外。Place the TypeScript files (.ts) outside of the wwwroot folder. 例如,将文件放在客户端文件夹中。For example, place the files in a Client folder.

  2. wwwroot文件夹配置 TypeScript 生成输出。Configure the TypeScript build output for the wwwroot folder. 在项目文件中的 PropertyGroup 内设置 TypescriptOutDir 属性:Set the TypescriptOutDir property inside of a PropertyGroup in the project file:

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  3. 将 TypeScript 目标作为 ResolveCurrentProjectStaticWebAssets 目标的依赖项,方法是将以下目标添加到项目文件中的 PropertyGroup 内:Include the TypeScript target as a dependency of the ResolveCurrentProjectStaticWebAssets target by adding the following target inside of a PropertyGroup in the project file:

    <ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
      CompileTypeScript;
      $(ResolveCurrentProjectStaticWebAssetsInputs)
    </ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
    

使用引用 RCL 中的内容Consume content from a referenced RCL

RCL 的wwwroot文件夹中包含的文件会公开给使用的应用的前缀 _content/{LIBRARY NAME}/The files included in the wwwroot folder of the RCL are exposed to the consuming app under the prefix _content/{LIBRARY NAME}/. 例如,名为Razor的库会导致 _content/Razor.Class.Lib/的静态内容的路径。For example, a library named Razor.Class.Lib results in a path to static content at _content/Razor.Class.Lib/.

使用应用引用库提供的静态资产,其中包含 <script><style><img>和其他 HTML 标记。The consuming app references static assets provided by the library with <script>, <style>, <img>, and other HTML tags. 使用的应用必须在 Startup.Configure中启用静态文件支持The consuming app must have static file support enabled in Startup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    app.UseStaticFiles();

    ...
}

从生成输出(dotnet run)运行使用应用时,默认情况下会在开发环境中启用静态 web 资产。When running the consuming app from build output (dotnet run), static web assets are enabled by default in the Development environment. 若要在从生成输出运行时支持其他环境中的资产,请在Program.cs中的主机生成器上调用 UseStaticWebAssetsTo support assets in other environments when running from build output, call UseStaticWebAssets on the host builder in Program.cs:

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)运行应用时,不需要调用 UseStaticWebAssetsCalling UseStaticWebAssets isn't required when running an app from published output (dotnet publish).

多项目开发流程Multi-project development flow

当使用中的应用运行时:When the consuming app runs:

  • RCL 中的资产保留在其原始文件夹中。The assets in the RCL stay in their original folders. 资产不会移动到使用的应用。The assets aren't moved to the consuming app.
  • 重新生成 RCL 后,RCL 的wwwroot文件夹内的任何更改都会反映在使用的应用程序中,而无需重新生成使用的应用。Any change within the RCL's wwwroot folder is reflected in the consuming app after the RCL is rebuilt and without rebuilding the consuming app.

生成 RCL 时,将生成描述静态 web 资产位置的清单。When the RCL is built, a manifest is produced that describes the static web asset locations. 使用的应用程序会在运行时读取清单,以使用来自引用项目和包的资产。The consuming app reads the manifest at runtime to consume the assets from referenced projects and packages. 将新资产添加到 RCL 时,必须重新生成 RCL 以更新其清单,然后使用的应用才能访问新资产。When a new asset is added to an RCL, the RCL must be rebuilt to update its manifest before a consuming app can access the new asset.

发布Publish

在发布应用程序时,所有被引用项目和包中的助理资产都将复制到 _content/{LIBRARY NAME}/下的已发布应用程序的wwwroot文件夹中。When the app is published, the companion assets from all referenced projects and packages are copied into the wwwroot folder of the published app under _content/{LIBRARY NAME}/.

Razor 视图、页、控制器、页模型、 razor 组件视图组件和数据模型可以内置于 Razor 类库(RCL)中。Razor views, pages, controllers, page models, Razor components, View components, and data models can be built into a Razor class library (RCL). RCL 可以打包并重复使用。The RCL can be packaged and reused. 应用程序可以包括 RCL,并重写其中包含的视图和页面。Applications can include the RCL and override the views and pages it contains. 如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml 文件)优先。When a view, partial view, or Razor Page is found in both the web app and the RCL, the Razor markup (.cshtml file) in the web app takes precedence.

查看或下载示例代码如何下载View or download sample code (how to download)

创建一个包含 Razor UI 的类库Create a class library containing Razor UI

  • 从 Visual Studio“文件”菜单中,选择“新建”>“项目”。From the Visual Studio File menu, select New > Project.
  • 选择“ASP.NET Core Web 应用程序”。Select ASP.NET Core Web Application.
  • 命名库(例如,“RazorClassLib”)>“确定”。Name the library (for example, "RazorClassLib") > OK. 为避免与已生成的视图库发生文件名冲突,请确保库名称不以 .Views 结尾。To avoid a file name collision with the generated view library, ensure the library name doesn't end in .Views.
  • 验证是否已选择 ASP.NET Core 2.1 或更高版本。Verify ASP.NET Core 2.1 or later is selected.
  • 选择Razor 类库> "确定"Select Razor Class Library > OK.

RCL 具有以下项目文件:An RCL has the following project file:

<Project Sdk="Microsoft.NET.Sdk.Razor">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
  </ItemGroup>

</Project>

将 Razor 文件添加到 RCL。Add Razor files to the RCL.

ASP.NET Core 模板假设 RCL 内容位于 "区域" 文件夹中。The ASP.NET Core templates assume the RCL content is in the Areas folder. 请参阅RCL Pages layout ,以创建 RCL,以在 ~/Pages 而不是 ~/Areas/Pages公开内容。See RCL Pages layout to create an RCL that exposes content in ~/Pages rather than ~/Areas/Pages.

引用 RCL 内容Reference RCL content

可以通过以下方式引用 RCL:The RCL can be referenced by:

演练:创建 RCL 项目并从 Razor Pages 项目使用Walkthrough: Create an RCL project and use from a Razor Pages project

可以下载并测试完整项目,无需创建项目。You can download the complete project and test it rather than creating it. 示例下载包含附加代码和链接,以方便测试项目。The sample download contains additional code and links that make the project easy to test. 可以在此 GitHub 问题中留下反馈,评论下载示例和分步说明的对比。You can leave feedback in this GitHub issue with your comments on download samples versus step-by-step instructions.

测试下载应用Test the download app

如果尚未下载已完成的应用,并更愿意创建演练项目,请跳转至下一节If you haven't downloaded the completed app and would rather create the walkthrough project, skip to the next section.

在 Visual Studio 中打开 .sln 文件。Open the .sln file in Visual Studio. 运行应用。Run the app.

“测试 Test WebApp1”中的说明进行操作Follow the instructions in Test WebApp1

创建 RCLCreate an RCL

在本部分中,将创建一个 RCL。In this section, an RCL is created. 将 Razor 文件添加到 RCL。Razor files are added to the RCL.

创建 RCL 项目:Create the RCL project:

  • 从 Visual Studio“文件”菜单中,选择“新建”>“项目”。From the Visual Studio File menu, select New > Project.
  • 选择“ASP.NET Core Web 应用程序”。Select ASP.NET Core Web Application.
  • 将应用命名为 " RazorUIClassLib > " 确定 "Name the app RazorUIClassLib > OK.
  • 验证是否已选择 ASP.NET Core 2.1 或更高版本。Verify ASP.NET Core 2.1 or later is selected.
  • 选择Razor 类库> "确定"Select Razor Class Library > OK.
  • 添加一个名为 RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml 的 Razor 分部视图文件。Add a Razor partial view file named RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml.

将 Razor 文件和文件夹添加到项目Add Razor files and folders to the project

  • 使用以下代码替换 RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml 中的标记:Replace the markup in RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml with the following code:

    <h3>_Message.cshtml partial view.</h3>
    
    <p>RazorUIClassLib\Areas\MyFeature\Pages\Shared\_Message.cshtml</p>
    
  • 使用以下代码替换 RazorUIClassLib/Areas/MyFeature/Pages/Page1.cshtml 中的标记:Replace the markup in RazorUIClassLib/Areas/MyFeature/Pages/Page1.cshtml with the following code:

    @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@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers is required to use the partial view (<partial name="_Message" />). 可以添加一个 _ViewImports.cshtml 文件,无需包含 @addTagHelper 指令。Rather than including the @addTagHelper directive, you can add a _ViewImports.cshtml file. 例如:For example:

    dotnet new viewimports -o RazorUIClassLib/Areas/MyFeature/Pages
    

    有关 _ViewImports的详细信息,请参阅导入共享指令For more information on _ViewImports.cshtml, see Importing Shared Directives

  • 生成类库以验证是否不存在编译器错误:Build the class library to verify there are no compiler errors:

    dotnet build RazorUIClassLib
    

生成输出内容包含 RazorUIClassLib.dll 和 RazorUIClassLib.Views.dll。The build output contains RazorUIClassLib.dll and RazorUIClassLib.Views.dll. RazorUIClassLib.Views.dll 包含已编译的 Razor 内容。RazorUIClassLib.Views.dll contains the compiled Razor content.

从 Razor 页面项目使用 Razor UI 库Use the Razor UI library from a Razor Pages project

创建 Razor 页面 Web 应用:Create the Razor Pages web app:

  • 解决方案资源管理器中,右键单击解决方案 >添加> "新建项目"。From Solution Explorer, right-click the solution > Add > New Project.

  • 选择“ASP.NET Core Web 应用程序”。Select ASP.NET Core Web Application.

  • 将应用命名为 WebApp1。Name the app WebApp1.

  • 验证是否已选择 ASP.NET Core 2.1 或更高版本。Verify ASP.NET Core 2.1 or later is selected.

  • 选择 " Web 应用程序> " 确定 "Select Web Application > OK.

  • 在解决方案资源管理器中,右键单击“WebApp1”,然后选择“设为启动项目”。From Solution Explorer, right-click on WebApp1 and select Set as StartUp Project.

  • 解决方案资源管理器中,右键单击WebApp1 ,然后选择 "生成依赖关系 >项目依赖项"。From Solution Explorer, right-click on WebApp1 and select Build Dependencies > Project Dependencies.

  • 将 RazorUIClassLib 勾选为 WebApp1 的依赖项。Check RazorUIClassLib as a dependency of WebApp1.

  • 解决方案资源管理器中,右键单击WebApp1 ,然后选择 "添加>引用"。From Solution Explorer, right-click on WebApp1 and select Add > Reference.

  • 在 "引用管理器" 对话框中,选中 " RazorUIClassLib > " 确定 "In the Reference Manager dialog, check RazorUIClassLib > OK.

运行应用。Run the app.

测试 WebApp1Test WebApp1

浏览到 /MyFeature/Page1,验证 Razor UI 类库是否正在使用中。Browse to /MyFeature/Page1 to verify that the Razor UI class library is in use.

重写视图、分部视图和页面Override views, partial views, and pages

如果在 Web 应用和 RCL 中都能找到视图、分部视图或 Razor 页面,则 Web 应用中的 Razor 标记(.cshtml 文件)优先。When a view, partial view, or Razor Page is found in both the web app and the RCL, the Razor markup (.cshtml file) in the web app takes precedence. 例如,将WebApp1/Areas/MyFeature/Pages/Page1. cshtml添加到 WebApp1,WebApp1 中的 page1 将优先于 RCL 中的 page1。For example, add WebApp1/Areas/MyFeature/Pages/Page1.cshtml to WebApp1, and Page1 in the WebApp1 will take precedence over Page1 in the RCL.

在示例下载中,将 WebApp1/Areas/MyFeature2 重命名为 WebApp1/Areas/MyFeature 来测试优先级。In the sample download, rename WebApp1/Areas/MyFeature2 to WebApp1/Areas/MyFeature to test precedence.

将 RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml 分部视图复制到 WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml。Copy the RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml partial view to WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. 更新标记以指示新的位置。Update the markup to indicate the new location. 生成并运行应用,验证使用部分的应用版本。Build and run the app to verify the app's version of the partial is being used.

RCL 页面布局RCL Pages layout

若要引用 RCL 内容(如同它是 web 应用的Pages文件夹的一部分),请创建具有以下文件结构的 RCL 项目:To reference RCL content as though it is part of the web app's Pages folder, create the RCL project with the following file structure:

  • RazorUIClassLib/PagesRazorUIClassLib/Pages
  • RazorUIClassLib/Pages/SharedRazorUIClassLib/Pages/Shared

假设RazorUIClassLib/Pages/Shared包含两部分文件: _Header_FooterSuppose RazorUIClassLib/Pages/Shared contains two partial files: _Header.cshtml and _Footer.cshtml. 可以将 <partial> 标记添加到 _Layout文件中:The <partial> tags could be added to _Layout.cshtml file:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>