在类库中使用 ASP.NET 核心 API
作者:Scott Addie
本文档提供有关在类库中使用 ASP.NET 核心 API 的指导。 有关所有其他库指南,请参阅 开源库指南。
确定要支持哪些 ASP.NET 核心版本
ASP.NET Core 遵循 .NET Core 支持策略。 确定库中要支持哪些 ASP.NET 核心版本时,请参阅支持策略。 图书馆应该:
- 努力支持所有分类为 Long-Term 支持(LTS)的 ASP.NET Core 版本。
- 无需支持列为“生命周期结束”(EOL) 类别的 ASP.NET Core 版本。
由于 ASP.NET Core 预览版已推出,因此已在 aspnet/Announcements GitHub 存储库中发布中断性变更。 可以在开发框架功能时对库进行兼容性测试。
使用 ASP.NET Core 共享框架
随着 .NET Core 3.0 的发布,许多 ASP.NET 核心程序集不再作为包发布到 NuGet。 相反,程序集包含在 Microsoft.AspNetCore.App
共享框架中,该框架随 .NET Core SDK 和运行时安装程序一起安装。 若要查看不再发布的包列表,请参阅删除过时的包引用。
从 .NET Core 3.0 起,使用 Microsoft.NET.Sdk.Web
MSBuild SDK 的项目会隐式引用共享框架。 使用 Microsoft.NET.Sdk
或 Microsoft.NET.Sdk.Razor
SDK 的项目必须引用 ASP.NET Core 才能在共享框架中使用 ASP.NET 核心 API。
若要引用 ASP.NET Core,请将以下 <FrameworkReference>
元素添加到项目文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
包括 Blazor 扩展性
Blazor 支持为服务器端和客户端应用创建 Razor 组件 类库。 若要支持类库中的 Razor 组件,类库必须使用 Microsoft.NET.Sdk。Razor SDK。
支持服务器端和客户端应用
若要支持服务器端应用和客户端应用通过单个库使用 Razor 组件,请按照以下说明在编辑器中使用。
使用 Razor 类库 项目模板。
注意
不要选中“支持页面和视图”复选框。 选中复选框会导致类库仅支持服务器端应用。
从项目模板生成的库:
- 基于已安装的 SDK,定位当前的 .NET 框架。
- 通过将
browser
作为受支持的平台包含在SupportedPlatform
MSBuild 项中,启用有关平台依赖项的浏览器兼容性检查。 - 为 Microsoft.AspNetCore.Components.Web添加 NuGet 包引用。
RazorClassLibrary-CSharp.csproj
(参考源)
注意
指向 .NET 引用源的文档链接通常会加载存储库的默认分支,该分支代表正在进行的 .NET 下一版本的开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅 如何选择 ASP.NET 核心源代码的版本标记(dotnet/AspNetCore.Docs #26205)。
支持多个框架版本
如果库必须支持当前版本向 Blazor 添加的功能,同时还要支持一个或多个早期版本,则让库面向多个目标。 在 TargetFrameworks
MSBuild 属性中提供以分号分隔的目标框架名字对象 (TFM) 列表:
<TargetFrameworks>{TARGET FRAMEWORKS}</TargetFrameworks>
在前面的示例中,{TARGET FRAMEWORKS}
占位符表示分号分隔的TFM 列表。 例如,netcoreapp3.1;net5.0
。
仅支持服务器端使用
类库很少是设计为仅能支持服务器端应用的。 如果类库仅需要特定于服务器端的功能(如访问 CircuitHandler 或 Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage),或使用特定于 ASP.NET Core 的功能(如中间件、MVC 控制器或 Razor Pages),请使用以下方法之一:
使用“支持页面和视图”复选框 (Visual Studio) 或使用
dotnet new
命令搭配-s|--support-pages-and-views
选项创建库时,指定库支持页面和视图:dotnet new razorclasslib -s
仅提供对库项目文件中 ASP.NET Core 的框架引用以及对任何其他必需的 MS 生成属性的框架引用:
<ItemGroup> <FrameworkReference Include="Microsoft.AspNetCore.App" /> </ItemGroup>
有关包含 Razor 组件的库的详细信息,请参阅使用 Razor 类库 (RCL) 中的 ASP.NET Core Razor 组件。
包括 MVC 扩展性
本部分概述了针对图书馆的建议,其中包括:
此部分未探讨用于支持多个 MVC 版本的多目标。 有关支持多个 ASP.NET 核心版本的指南,请参阅 支持多个 ASP.NET 核心版本。
Razor 视图或 Razor 页面
包括 Razor 视图或 Razor 页面的项目必须使用 Microsoft.NET.Sdk.Razor SDK。
如果项目面向 .NET Core 3.x,则需要:
AddRazorSupportForMvc
MSBuild 属性设置为true
。- 具有针对共享框架的
<FrameworkReference>
元素。
Razor 类库 项目模板满足针对 .NET Core 的项目的上述要求。 请针对自己的编辑器使用以下说明。
使用 Razor 类库 项目模板。 应选中此模板的“支持页和视图”复选框。
例如:
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
若项目改为面向 .NET Standard,则需要 Microsoft.AspNetCore.Mvc 包引用。 Microsoft.AspNetCore.Mvc
包已移动到 ASP.NET Core 3.0 中的共享框架中,因此不再发布。 例如:
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
</ItemGroup>
</Project>
标记帮助程序
包含 标记帮助程序 的项目应使用 Microsoft.NET.Sdk
SDK。 如果面向 .NET Core 3.x,请为共享框架添加 <FrameworkReference>
元素。 例如:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
若面向 .NET Standard(以支持 ASP.NET Core 3.x 之前的版本),则添加对 Microsoft.AspNetCore.Mvc.Razor 的包引用。 Microsoft.AspNetCore.Mvc.Razor
包已移动到共享框架中,因此不再发布。 例如:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
</ItemGroup>
</Project>
查看组件
包含 视图组件 的项目应使用 Microsoft.NET.Sdk
SDK。 如果面向 .NET Core 3.x,请为共享框架添加 <FrameworkReference>
元素。 例如:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
若面向 .NET Standard(以支持 ASP.NET Core 3.x 之前的版本),则添加 Microsoft.AspNetCore.Mvc.ViewFeatures 的包引用。 Microsoft.AspNetCore.Mvc.ViewFeatures
包已移动到共享框架中,因此不再发布。 例如:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="2.2.0" />
</ItemGroup>
</Project>
支持多个 ASP.NET 核心版本
需要进行多目标设置以便于编写支持多个 ASP.NET Core 变体的程序库。 假设标记帮助程序库必须支持以下 ASP.NET 核心变体:
- 面向 .NET Framework 4.6.1 的 ASP.NET Core 2.1
- 面向 .NET Core 2.x 的 ASP.NET Core 2.x
- 面向 .NET Core 3.x 的 ASP.NET Core 3.x
以下项目文件通过 TargetFrameworks
属性支持这些变体:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net461</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Markdig" Version="0.16.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.1.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
上面的项目文件将完成以下操作:
- 为所有使用者添加
Markdig
包。 - 为面向 .NET Framework 4.6.1 或更高版本或者 .NET Core 2.x 的使用者添加对 Microsoft.AspNetCore.Mvc.Razor 的引用。 由于后向兼容性,包版本 2.1.0 适用于 ASP.NET Core 2.2。
- 为面向 .NET Core 3.x 的使用者引用共享框架。
Microsoft.AspNetCore.Mvc.Razor
包包含在共享框架中。
或者,可以将 .NET Standard 2.0 作为目标框架,而不是针对 .NET Core 2.1 和 .NET Framework 4.6.1。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Markdig" Version="0.16.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.1.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
使用上述项目文件时,存在以下注意事项:
- 由于该库仅包含标记帮助器,因此更容易将目标放在运行 ASP.NET Core 的特定平台上:.NET Core 和 .NET Framework。 其他符合 .NET Standard 2.0 的目标框架(如 Unity 和 UWP)不能使用标记帮助程序。
- 在 .NET Framework 中使用 .NET Standard 2.0 存在一些问题,这些问题在 .NET Framework 4.7.2 中得到了解决。 通过将目标设定为 .NET Framework 4.6.1,可以改善使用 .NET Framework 4.6.1 到 4.7.1 的消费者的体验。
如果您的库需要调用平台特定的 API,请将目标定为特定的 .NET 实现,而不是 .NET Standard。 有关详细信息,请参阅 多重目标设定。
使用未更改的 API
假设你正在将中间件库从 .NET Core 2.2 升级到 3.1。 库中使用的 ASP.NET 核心中间件 API 在 ASP.NET Core 2.2 和 3.1 之间没有更改。 若要继续支持 .NET Core 3.1 中的中间件库,请执行以下步骤:
- 按照 标准库指南操作。
- 如果共享框架中不存在相应的程序集,请为每个 API 的 NuGet 包添加包引用。
使用已修改的 API
假设你正在将库从 .NET Core 2.2 升级到 .NET Core 3.1。 库正在使用的 ASP.NET Core API 包含 ASP.NET Core 3.1 的中断性变更。 请考虑是否可以重写库,以在所有版本中不使用损坏的 API。
若可以重写此库,则进行重写,并通过包引用继续面向早期版本的目标框架(例如 .NET Standard 2.0 或 .NET Framework 4.6.1)。
如果无法重写库,请执行以下步骤:
- 为 .NET Core 3.1 添加目标。
- 为共享框架添加
<FrameworkReference>
元素。 - 将 #if 预处理器指令 与相应的目标框架符号一起使用,以有条件地编译代码。
例如,从 ASP.NET Core 3.1 起,默认禁用 HTTP 请求和响应流的同步读取和写入。 ASP.NET Core 2.2 默认支持同步行为。 可以考虑在中间件库中,当 I/O 操作发生时启用同步读写功能。 库应将代码括起来,以便在适当的预处理器指令中启用同步功能。 例如:
public async Task Invoke(HttpContext httpContext)
{
if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
{
httpContext.Response.StatusCode = (int) HttpStatusCode.OK;
httpContext.Response.ContentType = "application/json";
httpContext.Response.ContentLength = _bufferSize;
#if !NETCOREAPP3_1 && !NETCOREAPP5_0
var syncIOFeature = httpContext.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{
syncIOFeature.AllowSynchronousIO = true;
}
using (var sw = new StreamWriter(
httpContext.Response.Body, _encoding, bufferSize: _bufferSize))
{
_json.Serialize(sw, new JsonMessage { message = "Hello, World!" });
}
#else
await JsonSerializer.SerializeAsync<JsonMessage>(
httpContext.Response.Body, new JsonMessage { message = "Hello, World!" });
#endif
return;
}
await _next(httpContext);
}
使用 3.1 引入的 API
假设要使用 ASP.NET Core 3.1 中引入的 ASP.NET Core API。 请考虑以下问题:
- 库是否在功能上需要新的 API?
- 库能否以不同的方式实现此功能?
若此库在功能上需要此 API,并且没有实现它的下层方法:
- 仅面向 .NET Core 3.x。
- 为共享框架添加
<FrameworkReference>
元素。
如果库可以采用不同的方式实现该功能:
- 将 .NET Core 3.x 添加为目标框架。
- 为共享框架添加
<FrameworkReference>
元素。 - 将 #if 预处理器指令 与相应的目标框架符号一起使用,以有条件地编译代码。
例如,以下标记帮助程序使用 ASP.NET Core 3.1 中引入的 IWebHostEnvironment 接口。 面向 .NET Core 3.1 的使用者执行 NETCOREAPP3_1
目标框架符号定义的代码路径。 标记帮助程序的构造函数参数类型更改为 IHostingEnvironment,适用于 .NET Core 2.1 和 .NET Framework 4.6.1 的使用者。 此更改是必需的,因为 ASP.NET Core 3.1 将 IHostingEnvironment
标记为已过时,建议 IWebHostEnvironment
替换。
[HtmlTargetElement("script", Attributes = "asp-inline")]
public class ScriptInliningTagHelper : TagHelper
{
private readonly IFileProvider _wwwroot;
#if NETCOREAPP3_1
public ScriptInliningTagHelper(IWebHostEnvironment env)
#else
public ScriptInliningTagHelper(IHostingEnvironment env)
#endif
{
_wwwroot = env.WebRootFileProvider;
}
// code omitted for brevity
}
以下多目标项目文件支持此标记帮助器方案:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net461</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Markdig" Version="0.16.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.1.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
使用共享框架已删除的 API
若要使用从共享框架中删除的 ASP.NET Core 程序集,请添加相应的包引用。 有关从 ASP.NET Core 3.1 中的共享框架中删除的包的列表,请参阅 删除过时的包引用。
例如,若要添加 Web API 客户端,
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
</ItemGroup>
</Project>