从 ASP.NET Core 2.2 迁移到3.0

作者: Scott AddieRick Anderson

本文介绍如何将现有 ASP.NET Core 2.2 项目更新为 ASP.NET Core 3.0。

先决条件

在 global.json 中更新 .NET Core SDK 版本

如果解决方案依赖于全局 json文件来面向特定的 .NET Core SDK 版本,请将其 version 属性更新为安装在计算机上的3.0 版本:

{
  "sdk": {
    "version": "3.0.100"
  }
}

更新项目文件

更新目标框架

ASP.NET Core 3.0 及更高版本仅在 .NET Core 上运行。 目标框架名字对象(TFM)设置为 netcoreapp3.0

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

</Project>

删除过时的包引用

ASP.NET Core 3.0 不会生成大量 NuGet 包。 此类包引用应从项目文件中删除。 对于 ASP.NET Core 2.2 web 应用,请考虑以下项目文件:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App"/>
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
  </ItemGroup>

</Project>

ASP.NET Core 3.0 的更新项目文件:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

</Project>

更新的 ASP.NET Core 3.0 项目文件:

  • <PropertyGroup> 中:

    • 将 TFM 更新为 netcoreapp3.0
    • 删除 <AspNetCoreHostingModel> 元素。 有关详细信息,请参阅本文档中的进程内承载模型
  • <ItemGroup> 中:

    • 删除 Microsoft.AspNetCore.App 有关详细信息,请参阅本文档中的框架参考
    • 删除了 Microsoft.AspNetCore.Razor.Design,并且不再生成以下包列表。

若要查看不再生成的包的完整列表,请选择以下展开列表:

单击以展开不再生成的包列表
  • Microsoft.AspNetCore
  • Microsoft.AspNetCore.All
  • Microsoft.AspNetCore.App
  • Microsoft.AspNetCore.Antiforgery
  • Microsoft.AspNetCore.Authentication
  • Microsoft.AspNetCore.Authentication.Abstractions
  • Microsoft.AspNetCore.Authentication.Cookies
  • Microsoft.AspNetCore.Authentication.Core
  • Microsoft.AspNetCore.Authentication.OAuth
  • Microsoft.AspNetCore.Authorization.Policy
  • Microsoft.AspNetCore.CookiePolicy
  • Microsoft.AspNetCore.Cors
  • Microsoft.AspNetCore.Diagnostics
  • Microsoft.AspNetCore.Diagnostics.HealthChecks
  • Microsoft.AspNetCore.HostFiltering
  • Microsoft.AspNetCore.Hosting
  • Microsoft.AspNetCore.Hosting.Abstractions
  • Microsoft.AspNetCore.Hosting.Server.Abstractions
  • Microsoft.AspNetCore.Http
  • Microsoft.AspNetCore.Http.Abstractions
  • Microsoft.AspNetCore.Http.Connections
  • Microsoft.AspNetCore.Http.Extensions
  • Microsoft.AspNetCore.HttpOverrides
  • Microsoft.AspNetCore.HttpsPolicy
  • Microsoft.AspNetCore.Identity
  • Microsoft.AspNetCore.Localization
  • Microsoft.AspNetCore.Localization.Routing
  • Microsoft.AspNetCore.Mvc
  • Microsoft.AspNetCore.Mvc.Abstractions
  • Microsoft.AspNetCore.Mvc.Analyzers
  • Microsoft.AspNetCore.Mvc.ApiExplorer
  • Microsoft.AspNetCore.Mvc.Api.Analyzers
  • Microsoft.AspNetCore.Mvc.Core
  • Microsoft.AspNetCore.Mvc.Cors
  • Microsoft.AspNetCore.Mvc.DataAnnotations
  • Microsoft.AspNetCore.Mvc.Formatters.Json
  • Microsoft.AspNetCore.Mvc.Formatters.Xml
  • Microsoft.AspNetCore.Mvc.Localization
  • Microsoft.AspNetCore.Mvc.Razor
  • Microsoft.AspNetCore.Mvc.Razor.ViewCompilation
  • Microsoft.AspNetCore.Mvc.RazorPages
  • Microsoft.AspNetCore.Mvc.TagHelpers
  • Microsoft.AspNetCore.Mvc.ViewFeatures
  • Microsoft.AspNetCore.Razor
  • Microsoft.AspNetCore.Razor.Runtime
  • Microsoft.AspNetCore.Razor.Design
  • Microsoft.AspNetCore.ResponseCaching
  • Microsoft.AspNetCore.ResponseCaching.Abstractions
  • Microsoft.AspNetCore.ResponseCompression
  • Microsoft.AspNetCore.Rewrite
  • Microsoft.AspNetCore.Routing
  • Microsoft.AspNetCore.Routing.Abstractions
  • Microsoft.AspNetCore.Server.HttpSys
  • Microsoft.AspNetCore.Server.IIS
  • Microsoft.AspNetCore.Server.IISIntegration
  • Microsoft.AspNetCore.Server.Kestrel
  • Microsoft.AspNetCore.Server.Kestrel.Core
  • Microsoft.AspNetCore.Server.Kestrel.Https
  • Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
  • Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
  • Microsoft.AspNetCore.Session
  • AspNetCore。SignalR
  • AspNetCore.SignalR。转储
  • Microsoft.AspNetCore.StaticFiles
  • Microsoft.AspNetCore.WebSockets
  • Microsoft.AspNetCore.WebUtilities
  • Microsoft.Net

查看重大更改

查看重大更改

框架引用

通过上述某个包提供的 ASP.NET Core 功能可作为 Microsoft.AspNetCore.App 共享框架的一部分提供。 共享框架是安装在计算机上并包括运行时组件和目标包的一组程序集( .dll 文件)。 有关详细信息,请参阅共享框架

  • 面向 Microsoft.NET.Sdk.Web SDK 的项目隐式引用 Microsoft.AspNetCore.App 框架。

    对于这些项目,不需要其他引用:

    <Project Sdk="Microsoft.NET.Sdk.Web">
      <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
      </PropertyGroup>
        ...
    </Project>
    
  • 面向 Microsoft.NET.SdkMicrosoft.NET.Sdk.Razor SDK 的项目应将显式 FrameworkReference 添加到 Microsoft.AspNetCore.App

    <Project Sdk="Microsoft.NET.Sdk.Razor">
      <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
      </ItemGroup>
        ...
    </Project>
    

使用 Docker 的依赖框架的生成

使用依赖于 ASP.NET Core共享框架的包的、依赖于框架的控制台应用程序可能会给出以下运行时错误:

It was not possible to find any compatible framework version
The specified framework 'Microsoft.AspNetCore.App', version '3.0.0' was not found.
  - No frameworks were found.

Microsoft.AspNetCore.App 是包含 ASP.NET Core 运行时的共享框架,只存在于dotnet/Core/aspnet Docker 映像中。 3.0 SDK 使用 ASP.NET Core 来减小依赖于框架的生成的大小,但不包括共享框架中可用的库的重复副本。 这可能会节省高达 18 MB,但需要提供 ASP.NET Core 运行时才能运行应用。

若要确定应用程序在 ASP.NET Core 共享框架上是否具有依赖关系(直接或间接),请检查应用程序生成/发布期间生成的runtimeconfig.template.json文件。 以下 JSON 文件显示了对 ASP.NET Core 共享框架的依赖项:

{
  "runtimeOptions": {
    "tfm": "netcoreapp3.0",
    "framework": {
      "name": "Microsoft.AspNetCore.App",
      "version": "3.0.0"
    },
    "configProperties": {
      "System.GC.Server": true
    }
  }
}

如果你的应用使用的是 Docker,请使用包含 ASP.NET Core 3.0 的基本映像。 例如,docker pull mcr.microsoft.com/dotnet/core/aspnet:3.0

添加已删除程序集的包引用

ASP.NET Core 3.0 删除了之前属于 Microsoft.AspNetCore.App 包引用的某些程序集。 若要可视化删除了哪些程序集,请比较两个共享框架文件夹。 例如,2.2.7 和3.0.0 版本的比较:

共享框架程序集比较

若要继续使用已删除程序集提供的功能,请参考相应包的3.0 版本:

  • 使用单个用户帐户的模板生成的 web 应用需要添加以下包:

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
      <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
        <UserSecretsId>My-secret</UserSecretsId>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="3.0.0" />
        <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0" />
        <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="3.0.0" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0" />
      </ItemGroup>
    
    </Project>
    
  • Microsoft.entityframeworkcore

    有关引用数据库提供程序特定包的详细信息,请参阅数据库提供程序

  • 标识 UI

    可以通过引用AspNetCore包来添加对标识 UI的支持。

  • SPA 服务

  • 第三方身份验证流的身份验证 – 支持作为 NuGet 包提供:

  • System.Net.HttpClient – 的格式和内容协商支持对WebApi NuGet 包的提供了很好的扩展性,可用于 System.Net.HttpClientReadAsAsyncPostJsonAsync等 api。

  • Razor 运行时编译 – 对 Razor 视图和页面的运行时编译的支持现在是RuntimeCompilation的一部分。

  • MVC Newtonsoft.Json (Json.NET)支持将 MVC 与 Newtonsoft.Json 结合使用 – 支持现在属于NewtonsoftJson

启动更改

下图显示了 ASP.NET Core 2.2 Razor Pages Web 应用中已删除和已更改的行:

ASP.NET Core 2.2 Razor Web 应用中的已删除和已更改的行

在上图中,删除的代码显示为红色。 删除的代码不显示 cookie 选项代码,该代码在比较文件之前已被删除。

下图显示了 ASP.NET Core 3.0 Razor Pages Web 应用中添加和更改的行:

ASP.NET Core 3.0 Razor Web 应用中添加和更改的行

在上图中,添加的代码显示为绿色。 有关以下更改的信息:

分析器支持

目标为 Microsoft.NET.Sdk.Web 隐式引用分析器作为AspNetCore包的一部分交付的项目。 不需要其他引用即可启用这些。

如果你的应用使用以前使用AspNetCore包交付的API 分析器,则编辑项目文件以引用作为 .net Core Web SDK 的一部分提供的分析器:

<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
        <IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
    </PropertyGroup>

    ...
</Project>

Razor 类库

为 MVC 提供 UI 组件的 Razor 类库项目必须在项目文件中设置 AddRazorSupportForMvc 属性:

<PropertyGroup>
  <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>

进程内托管模型

项目默认为 ASP.NET Core 3.0 或更高版本中的进程内承载模型 如果项目文件的值为 InProcess,则可以选择删除项目文件中的 <AspNetCoreHostingModel> 属性。

Kestrel

配置

将 Kestrel 配置迁移到 ConfigureWebHostDefaultsProgram.cs)提供的 web 主机生成器:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(serverOptions =>
            {
                // Set properties and call methods on options
            })
            .UseStartup<Startup>();
        });

如果应用通过 HostBuilder手动创建宿主,请在 ConfigureWebHostDefaults中的 web 主机生成器上调用 UseKestrel

public static void Main(string[] args)
{
    var host = new HostBuilder()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseKestrel(serverOptions =>
            {
                // Set properties and call methods on options
            })
            .UseIISIntegration()
            .UseStartup<Startup>();
        })
        .Build();

    host.Run();
}

连接中间件替代连接适配器

已从 Kestrel 中删除连接适配器(Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal.IConnectionAdapter)。 将连接适配器替换为连接中间件。 连接中间件与 ASP.NET Core 管道中的 HTTP 中间件类似,但对于较低级别的连接。 HTTPS 和连接日志记录:

  • 已从连接适配器移到连接中间件。
  • 这些扩展方法的工作方式与 ASP.NET Core 以前版本相同。

有关详细信息,请参阅Kestrel 文章的 ListenOptions 部分中的 TlsFilterConnectionHandler 示例

已移动并公开传输抽象

Kestrel 传输层已作为 Connections.Abstractions 中的公共接口公开。 作为这些更新的一部分:

  • 已删除 Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions 和关联的类型。
  • NoDelay 已从 ListenOptions 转移到传输选项。
  • 已从 KestrelServerOptions中删除 Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal.SchedulingMode

有关详细信息,请参阅以下 GitHub 资源:

Kestrel 请求尾端标头

对于面向 ASP.NET Core 早期版本的应用:

  • Kestrel 将 HTTP/1.1 分块尾端标头添加到请求标头集合。
  • 在将请求正文读取到末尾后,尾端可用。

这会导致一些有关标头和尾部的歧义的问题,因此,在3.0 中,已将尾端移动到新集合(RequestTrailerExtensions)。

HTTP/2 请求尾端包括:

  • ASP.NET Core 2.2 中不可用。
  • 在3.0 中提供 RequestTrailerExtensions

提供了新的请求扩展方法来访问这些尾端。 与 HTTP/1.1 一样,在请求正文读取到末尾后,尾端可用。

3.0 版本提供以下 RequestTrailerExtensions 方法:

  • GetDeclaredTrailers – 获取请求 Trailer 标头,该标头列出了主体后预期的尾部。
  • SupportsTrailers – 指示请求是否支持接收尾端标头。
  • CheckTrailersAvailable – 检查请求是否支持尾端以及是否可供读取。 此检查未假定有要读取的尾端。 即使此方法返回 true,也没有要读取的尾部。
  • GetTrailer – 从响应中获取请求的尾随标头。 在调用 GetTrailer之前检查 SupportsTrailers,如果请求不支持尾部标头,则可能会出现 NotSupportedException

有关详细信息,请参阅将请求尾端置于单独的集合中(dotnet/AspNetCore #10410)

已禁用 AllowSynchronousIO

AllowSynchronousIO 启用或禁用同步 IO Api,如 HttpRequest.Body.ReadHttpResponse.Body.WriteStream.Flush 这些 Api 是线程不足的源,导致应用崩溃。 在 3.0 中,默认情况下禁用 AllowSynchronousIO 有关详细信息,请参阅Kestrel 文章中的同步 IO 部分

如果需要同步 IO,可以通过在所使用的服务器上配置 AllowSynchronousIO 选项来启用该功能(例如,在调用 ConfigureKestrel时(例如,如果使用 Kestrel)。 请注意,服务器(Kestrel、HttpSys、TestServer 等)都有自己的 AllowSynchronousIO 选项,此选项不会影响其他服务器。 可以使用 IHttpBodyControlFeature.AllowSynchronousIO 选项,按请求为所有服务器启用同步 IO:

var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>();

if (syncIOFeature != null)
{
    syncIOFeature.AllowSynchronousIO = true;
}

如果对在Dispose中调用同步 api 的 TextWriter 实现或其他流有问题,请改为调用新的 DisposeAsync API。

有关详细信息,请参阅[公告] AllowSynchronousIO 在所有服务器中禁用(dotnet/AspNetCore #7644)

AspNetCore. Kestrel 程序集

在 ASP.NET Core 2.1 中,AspNetCore 的内容已移至 AspNetCore。 Kestrel. Kestrel的内容已移至。 这是使用 TypeForwardedTo 特性的非重大更新。 对于3.0,已删除AspNetCore程序集和 NuGet 包的空 Kestrel 程序集。

引用AspNetCore的库应将 ASP.NET Core 依赖项更新为2.1 或更高版本。

目标为 ASP.NET Core 2.1 或更高版本的应用程序和库应删除对Kestrel包的任何直接引用。

Newtonsoft.json (Json.NET)支持

作为改善 ASP.NET Core 共享框架的工作的一部分,已从 ASP.NET Core 共享框架中删除newtonsoft.json (Json.NET)

ASP.NET Core 的默认 JSON 序列化程序现已 System.Text.Json,这是 .NET Core 3.0 中的新增项。 如果可能,请考虑使用 System.Text.Json 它是高性能的,不需要额外的库依赖项。 但是,由于 System.Text.Json 是新的,因此它当前可能缺少应用需要的功能。 有关详细信息,请参阅如何从 newtonsoft.json 迁移到 system.object

在 ASP.NET Core 3.0 SignalR 项目中使用 Newtonsoft.json

  • 安装SignalRAspNetCore。NewtonsoftJson NuGet 包。

  • 在客户端上,将 AddNewtonsoftJsonProtocol 方法调用链接到 HubConnectionBuilder 实例:

    new HubConnectionBuilder()
        .WithUrl("/chatHub")
        .AddNewtonsoftJsonProtocol(...)
        .Build();
    
  • 在服务器上,将 AddNewtonsoftJsonProtocol 方法调用链接到 Startup.ConfigureServices中的 AddSignalR 方法调用:

    services.AddSignalR()
        .AddNewtonsoftJsonProtocol(...);
    

在 ASP.NET Core 3.0 MVC 项目中使用 Newtonsoft.json

  • 安装AspNetCore NewtonsoftJson包。

  • 更新 Startup.ConfigureServices 以调用 AddNewtonsoftJson

    services.AddMvc()
        .AddNewtonsoftJson();
    

    AddNewtonsoftJson 与新 MVC 服务注册方法兼容:

    • AddRazorPages
    • AddControllersWithViews
    • AddControllers
    services.AddControllers()
        .AddNewtonsoftJson();
    

    可以在对 AddNewtonsoftJson的调用中设置 Newtonsoft.Json 设置:

    services.AddMvc()
        .AddNewtonsoftJson(options =>
               options.SerializerSettings.ContractResolver =
                  new CamelCasePropertyNamesContractResolver());
    

注意: 如果 AddNewtonsoftJson 方法不可用,请确保已安装AspNetCore NewtonsoftJson包。 常见的错误是安装newtonsoft.json包,而不是AspNetCore NewtonsoftJson包。

MVC 服务注册

ASP.NET Core 3.0 添加了用于在 Startup.ConfigureServices中注册 MVC 方案的新选项。

IServiceCollection 上的 MVC 方案相关的三个新的顶级扩展方法可用。 模板使用这些新方法,而不是 AddMvc AddMvc 会继续按照以前版本中的方式运行。

下面的示例添加了对控制器和 API 相关功能的支持,但不支持视图或页面。 API 模板使用以下代码:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}

下面的示例添加了对控制器、API 相关功能和视图(而不是页)的支持。 Web 应用程序(MVC)模板使用以下代码:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
}

以下示例添加了对 Razor Pages 和最小控制器支持的支持。 Web 应用程序模板使用以下代码:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
}

新方法也可以组合在一起。 下面的示例等效于在 ASP.NET Core 2.2 中调用 AddMvc

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
}

路由启动代码

如果应用调用 UseMvcUseSignalR,则将应用迁移到终结点路由(如果可能)。 若要改善与以前版本的 MVC 的终结点路由兼容性,我们已还原 ASP.NET Core 2.2 中引入的 URL 生成的某些更改。 如果在2.2 中使用终结点路由时遇到问题,则需要 ASP.NET Core 3.0 中的改进,但有以下例外:

  • 如果应用实现 IRouter 或继承自 Route,请使用DynamicRouteValuesTransformer作为替换。

  • 如果应用直接访问 MVC 内的 RouteData.Routers 以分析 Url,则可以将其替换为使用 LinkParser.ParsePathByEndpointName

  • 使用路由名称定义路由。

  • 使用 LinkParser.ParsePathByEndpointName 并传入所需的路由名称。

终结点路由支持与 IRouter相同的路由模式语法和路由模式创作功能。 终结点路由支持 IRouteConstraint 终结点路由支持 [Route][HttpGet]和其他 MVC 路由属性。

对于大多数应用程序,只 Startup 需要更改。

迁移Startup.Configure

一般建议:

  • 添加 UseRouting

  • 如果应用调用 UseStaticFiles,请将 UseStaticFiles 置于 UseRouting之前

  • 如果应用使用身份验证/授权功能(如 AuthorizePage[Authorize]),请将对 UseAuthenticationUseAuthorization的调用放在之后UseRoutingUseCors,但在 UseEndpoints之前:

    public void Configure(IApplicationBuilder app)
    {
      ...
    
      app.UseStaticFiles();
    
      app.UseRouting();
      app.UseCors();
    
      app.UseAuthentication();
      app.UseAuthorization();
    
      app.UseEndpoints(endpoints => {
         endpoints.MapControllers();
      });
    
  • UseEndpoints替换 UseMvcUseSignalR

  • 如果应用使用cors方案(如 [EnableCors]),请将对 UseCors 的调用放置在使用 cors 的任何其他中间件之前(例如,将 UseCors 置于 UseAuthenticationUseAuthorizationUseEndpoints之前)。

  • IHostingEnvironment 替换为 IWebHostEnvironment 并为 Microsoft.Extensions.Hosting 命名空间添加 using 语句。

  • IApplicationLifetime 替换为 IHostApplicationLifetimeMicrosoft.Extensions.Hosting 命名空间)。

  • EnvironmentName 替换为 EnvironmentsMicrosoft.Extensions.Hosting 命名空间)。

下面的代码是典型的 ASP.NET Core 2.2 应用程序 Startup.Configure 的示例:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseStaticFiles();

    app.UseAuthentication();

    app.UseSignalR(hubs =>
    {
        hubs.MapHub<ChatHub>("/chat");
    });

    app.UseMvc(routes =>
    {
        routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
}

更新以前的 Startup.Configure 代码后:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseStaticFiles();

    app.UseRouting();

    app.UseCors();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<ChatHub>("/chat");
        endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
}

警告

对于大多数应用,对 UseAuthenticationUseAuthorizationUseCors 的调用必须出现在对 UseRouting 的调用之间,然后 UseEndpoints 才有效。

运行状况检查

运行状况检查将终结点路由与泛型主机一起使用。 Startup.Configure 内,使用终结点 URL 或相对路径在终结点生成器上调用 MapHealthChecks

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
});

运行状况检查终结点可以:

  • 指定一个或多个允许的主机/端口。
  • 需要授权。
  • 需要 CORS。

有关详细信息,请参阅 ASP.NET Core 中的运行状况检查

安全中间件指南

对授权和 CORS 的支持是围绕中间件方法统一的。 这允许在这些情况下使用相同的中间件和功能。 此版本提供了更新的授权中间件,并增强了 CORS 中间件,使其能够理解 MVC 控制器使用的属性。

CORS

以前,CORS 可能比较困难。 在某些用例中提供了中间件,但在其他用例中使用中间件即可使用 MVC 筛选器。 使用 ASP.NET Core 3.0,建议所有需要 CORS 的应用都将 CORS 中间件与端点路由一起使用。 UseCors 可以与默认策略一起提供,并且可以使用 [EnableCors][DisableCors] 特性来重写所需的默认策略。

在下例中:

  • 已为具有 default 命名策略的所有终结点启用 CORS。
  • MyController 类将通过 [DisableCors] 特性来禁用 CORS。
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseCors("default");

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

[DisableCors]
public class MyController : ControllerBase
{
    ...
}

授权

在早期版本的 ASP.NET Core 中,通过 [Authorize] 属性提供授权支持。 授权中间件不可用。 在 ASP.NET Core 3.0 中,授权中间件是必需的。 建议在 UseAuthentication之后立即放置 ASP.NET Core 授权中间件(UseAuthorization)。 授权中间件还可以使用默认策略进行配置,该策略可以重写。

在 ASP.NET Core 3.0 或更高版本中,UseAuthorizationStartup.Configure中调用,以下 HomeController 需要已登录的用户:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

public class HomeController : Controller
{
    [Authorize]
    public IActionResult BuyWidgets()
    {
        ...
    }
}

使用终结点路由时,建议不要配置 <xref:Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter>,而是依赖授权中间件。 如果应用将 AuthorizeFilter 用作 MVC 中的全局筛选器,我们建议重构代码,以便在对 AddAuthorization的调用中提供策略。

DefaultPolicy 最初配置为要求身份验证,因此无需进行其他配置。 在下面的示例中,MVC 端点标记为 RequireAuthorization,以便所有请求都必须基于 DefaultPolicy进行授权。 但是,HomeController 允许在用户登录到应用时不登录,因为 [AllowAnonymous]

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute().RequireAuthorization();
    });
}

[AllowAnonymous]
public class HomeController : Controller
{
    ...
}

针对特定终结点的授权

还可以为特定的终结点类配置授权。 下面的代码示例将配置全局 AuthorizeFilter 的 MVC 应用转换为具有需要授权的特定策略的应用:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    static readonly string _RequireAuthenticatedUserPolicy = 
                            "RequireAuthenticatedUserPolicy";
    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(
                 options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        // Pre 3.0:
        // services.AddMvc(options => options.Filters.Add(new AuthorizeFilter(...));

        services.AddControllersWithViews();
        services.AddRazorPages();
        services.AddAuthorization(o => o.AddPolicy(_RequireAuthenticatedUserPolicy,
                        builder => builder.RequireAuthenticatedUser()));

    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute()
                .RequireAuthorization(_RequireAuthenticatedUserPolicy);
            endpoints.MapRazorPages();
        });
    }
}

还可以自定义策略。 DefaultPolicy 配置为要求身份验证:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(
                 options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddControllersWithViews();
        services.AddRazorPages();
        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new AuthorizationPolicyBuilder()
              .RequireAuthenticatedUser()
              .Build();
        });

    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute().RequireAuthorization();
            endpoints.MapRazorPages();
        });
    }
}
[AllowAnonymous]
public class HomeController : Controller
{

或者,通过配置 FallbackPolicy,可以将所有终结点配置为要求无 [Authorize]RequireAuthorization 的授权。 FallbackPolicyDefaultPolicy不同。 DefaultPolicy[Authorize]RequireAuthorization触发,而当未设置其他策略时,将触发 FallbackPolicy FallbackPolicy 最初配置为允许未经授权的请求。

下面的示例与前面 DefaultPolicy 示例相同,但使用 FallbackPolicy 总是要求对所有终结点进行身份验证,但指定 [AllowAnonymous] 时除外:

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddAuthorization(options =>
    {
        options.FallbackPolicy = new AuthorizationPolicyBuilder()
          .RequireAuthenticatedUser()
          .Build();
    });
}

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

[AllowAnonymous]
public class HomeController : Controller
{
    ...
}

中间件的授权工作正常,无需使用任何特定的授权知识。 例如,运行状况检查没有特定的授权知识,但运行状况检查可以具有由中间件应用的可配置授权策略。

此外,每个终结点都可以自定义其授权要求。 在下面的示例中,UseAuthorization 处理 DefaultPolicy的授权,但是 /healthz 运行状况检查终结点需要 admin 用户:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints
            .MapHealthChecks("/healthz")
            .RequireAuthorization(new AuthorizeAttribute(){ Roles = "admin", });
    });
}

在某些情况下,实现保护。 如果由于缺少中间件而跳过授权或 CORS 策略,则终结点中间件会引发异常。 提供有关配置错误的其他反馈的分析器支持。

自定义授权处理程序

如果应用使用自定义授权处理程序,则终结点路由将不同于 MVC 的资源类型传递给处理程序。 需要更新授权处理程序上下文资源为 AuthorizationFilterContext 类型的处理程序(由 MVC 筛选器提供的资源类型)以处理 RouteEndpoint 类型的资源(由端点路由提供给授权处理程序的资源类型)。

MVC 仍使用 AuthorizationFilterContext 资源,因此,如果应用程序使用 MVC 授权筛选器以及终结点路由授权,则可能有必要处理这两种类型的资源。

SignalR

SignalR 集线器的映射现在发生在 UseEndpoints内。

将每个中心与 MapHub映射。 与早期版本一样,每个中心都显式列出。

在以下示例中,添加了对 ChatHub SignalR 中心的支持:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<ChatHub>();
    });
}

有一个新的选项可用于控制来自客户端的消息大小限制。 例如,在 Startup.ConfigureServices 中:

services.AddSignalR(hubOptions =>
{
    hubOptions.MaximumReceiveMessageSize = 32768;
});

在 ASP.NET Core 2.2 中,可以设置 TransportMaxBufferSize 并有效控制最大消息大小。 在 ASP.NET Core 3.0 中,该选项现在仅控制观察反压之前的最大大小。

MVC 控制器

控制器的映射现在发生在 UseEndpoints中。

如果应用使用属性路由,则添加 MapControllers 由于路由包括对 ASP.NET Core 3.0 或更高版本中的多个框架的支持,因此添加属性路由控制器是可选的。

替换以下内容:

  • MapRouteMapControllerRoute
  • MapAreaRouteMapAreaControllerRoute

由于路由现在不仅包括对 MVC 的支持,术语已更改,使这些方法清楚地说明它们的作用。 传统路由(例如 MapControllerRoute/MapAreaControllerRoute/MapDefaultControllerRoute 将按照它们的添加顺序进行应用。 首先放置更具体的路由(如区域的路由)。

在下例中:

  • MapControllers 增加了对属性路由控制器的支持。
  • MapAreaControllerRoute 为某个区域中的控制器添加传统路由。
  • MapControllerRoute 为控制器添加传统路由。
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapAreaControllerRoute(
            "admin",
            "admin",
            "Admin/{controller=Home}/{action=Index}/{id?}");
        endpoints.MapControllerRoute(
            "default", "{controller=Home}/{action=Index}/{id?}");
    });
}

从控制器操作名称中删除 Async 后缀

在 ASP.NET Core 3.0 中,ASP.NET Core MVC 从控制器操作名称中删除 Async 后缀。 此新默认设置会影响路由和链接的生成。 例如:

public class ProductsController : Controller
{
    public async Task<IActionResult> ListAsync()
    {
        var model = await _dbContext.Products.ToListAsync();
        return View(model);
    }
}

在 ASP.NET Core 3.0 之前:

  • 可以在Products/batchmanagementclient.account.listasync路由中访问上述操作。

  • 需要指定 Async 后缀的链接生成。 例如:

    <a asp-controller="Products" asp-action="ListAsync">List</a>
    

在 ASP.NET Core 3.0:

  • 可以在产品/列表路由上访问上述操作。

  • 链接生成不需要指定 Async 后缀。 例如:

    <a asp-controller="Products" asp-action="List">List</a>
    

此更改不会影响使用[ActionName]特性指定的名称。 可以在 Startup.ConfigureServices中通过以下代码禁用默认行为:

services.AddMvc(options =>
    options.SuppressAsyncSuffixInActionNames = false);

如文档中所述,与早期版本的路由的不同之处在于,链接生成有一些不同之处(例如,使用 Url.Link 和类似的 api)。 其中包括:

  • 默认情况下,使用终结点路由时,不一定要保留生成的 Uri 中路由参数的大小写。 此行为可通过 IOutboundParameterTransformer 接口进行控制。
  • 为无效路由(不存在的控制器/操作或页)生成 URI 将在终结点路由下生成空字符串,而不是生成无效的 URI。
  • 环境值(来自当前上下文的路由参数)不会自动用于通过终结点路由生成的链接。 以前,当生成指向另一操作(或页)的链接时,将从当前路由的环境值推断出未指定的路由值。 使用终结点路由时,必须在生成链接期间显式指定所有路由参数。

Razor 页面

映射 Razor Pages 现在发生在 UseEndpoints内。

如果应用使用 Razor Pages,则添加 MapRazorPages 由于终结点路由包含对多个框架的支持,因此添加 Razor Pages 现在将选择加入。

在下面的 Startup.Configure 方法中,MapRazorPages 添加了 Razor Pages 支持:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

使用不带终结点路由的 MVC

若要在 ASP.NET Core 3.0 中通过 UseMvcUseMvcWithDefaultRoute 使用 MVC,需要在 Startup.ConfigureServices内显式选择加入。 这是必需的,因为 MVC 必须知道它是否可以在初始化期间依赖于授权和 CORS 中间件。 如果应用程序尝试使用不受支持的配置,则会发出警告。

如果应用需要旧的 IRouter 支持,请使用 Startup.ConfigureServices中的以下任意方法禁用 EnableEndpointRouting

services.AddMvc(options => options.EnableEndpointRouting = false);
services.AddControllers(options => options.EnableEndpointRouting = false);
services.AddControllersWithViews(options => options.EnableEndpointRouting = false);
services.AddRazorPages().AddMvcOptions(options => options.EnableEndpointRouting = false);

运行状况检查

运行状况检查可用作使用终结点路由的路由器软件。

添加 MapHealthChecks 以将运行状况检查与终结点路由一起使用。 MapHealthChecks 方法接受类似于 UseHealthChecks的参数。 使用 MapHealthChecks 超出 UseHealthChecks 的优点是能够应用授权,并对匹配策略进行更精细的控制。

在下面的示例中,为 /healthz上的运行状况检查终结点调用 MapHealthChecks

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHealthChecks("/healthz", new HealthCheckOptions() { });
    });
}

HostBuilder 替换 WebHostBuilder

ASP.NET Core 3.0 模板使用泛型主机 以前的版本使用Web 主机 下面的代码显示 Program 类生成的 ASP.NET Core 3.0 模板:

// requires using Microsoft.AspNetCore.Hosting;
// requires 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.UseStartup<Startup>();
            });
}

下面的代码演示 ASP.NET Core 2.2 模板生成 Program 类:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

IWebHostBuilder 保留在3.0,并且是前面的代码示例中所见 webBuilder 的类型。 未来版本中将弃用 WebHostBuilder,并将其替换为 HostBuilder

WebHostBuilderHostBuilder 的最重大更改是依赖关系注入(DI) 使用 HostBuilder时,只能将以下内容注入 Startup的构造函数中:

HostBuilder DI 约束:

  • 启用仅生成一次 DI 容器。
  • 避免产生的对象生存期问题,如解析多个单一实例实例。

有关详细信息,请参阅避免启动服务注入 ASP.NET Core 3

AddAuthorization 已移动到不同的程序集

AspNetCore中的 ASP.NET Core 2.2 和更低 AddAuthorization 方法:

  • AddAuthorizationCore重命名。
  • 已被移动到AspNetCore中。

同时使用AspNetCoreAspNetCore的应用都不会受到任何影响。)。

不是使用AspNetCore的应用程序应执行以下操作之一:

  • 将引用添加到AspNetCore中。 这种方法适用于大多数应用,只是必需的。
  • 切换到使用 AddAuthorizationCore

有关详细信息,请参阅AddAuthorization(o =>中的重大更改) #386 中存在不同的程序集

标识 UI

ASP.NET Core 3.0 的标识 UI 更新:

  • AspNetCore添加包引用。
  • 不使用 Razor Pages 的应用必须调用 MapRazorPages 请参阅本文档中的Razor Pages
  • 启动4是默认的 UI 框架。 设置 IdentityUIFrameworkVersion 项目属性以更改默认值。 有关详细信息,请参阅此 GitHub 公告

SignalR

SignalR JavaScript 客户端已从 @aspnet/signalr 改为 @microsoft/signalr 若要对此更改做出反应,请更改package文件、require 语句和 ECMAScript import 语句中的引用。

System.web 是默认协议

System.Text.Json 现在是客户端和服务器使用的默认集线器协议。

Startup.ConfigureServices中,调用 AddJsonProtocol 设置序列化程序选项。

服务

services.AddSignalR(...)
        .AddJsonProtocol(options =>
        {
            options.PayloadSerializerOptions.WriteIndented = false;
        })

客户端:

new HubConnectionBuilder()
    .WithUrl("/chatHub")
    .AddJsonProtocol(options =>
    {
        options.PayloadSerializerOptions.WriteIndented = false;
    })
    .Build();

切换到 Newtonsoft.json

如果使用的是newtonsoft.json 中不支持的功能,则可以切换回 Newtonsoft.Json 请参阅本文前面的ASP.NET Core 3.0 SignalR 项目中的使用 newtonsoft.json

Redis 分布式缓存

Redis包不适用于 ASP.NET Core 3.0 或更高版本的应用。 将包引用替换为StackExchangeRedis 有关详细信息,请参阅 ASP.NET Core 中的分布式缓存

选择启用运行时编译

在 ASP.NET Core 3.0 之前,视图的运行时编译是框架的隐式功能。 运行时编译对视图的生成时编译进行了补充。 它允许框架在修改文件时编译 Razor 视图和页面(cshtml文件),而无需重新生成整个应用。 此功能支持在 IDE 中进行快速编辑并刷新浏览器以查看更改的方案。

在 ASP.NET Core 3.0 中,运行时编译是一个可选方案。 生成时编译是默认情况下启用的视图编译机制。 当检测到dotnet文件的更改时,运行时依赖于 Visual Studio 或 Visual Studio Code 以重新生成项目。 在 Visual Studio 中,将运行的项目(Ctrl + F5)更改为 .cs、.csrazor 文件,但不进行调试(F5),这会触发项目的重新编译。

在 ASP.NET Core 3.0 项目中启用运行时编译:

  1. 安装 Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation NuGet 包。

  2. 更新 Startup.ConfigureServices 以调用 AddRazorRuntimeCompilation

    对于 ASP.NET Core MVC,请使用以下代码:

    services.AddControllersWithViews()
        .AddRazorRuntimeCompilation(...);
    

    对于 ASP.NET Core Razor Pages,请使用以下代码:

    services.AddRazorPages()
        .AddRazorRuntimeCompilation(...);
    

https://github.com/aspnet/samples/tree/master/samples/aspnetcore/mvc/runtimecompilation 的示例演示了在开发环境中有条件地启用运行时编译的示例。

有关 Razor 文件编译的详细信息,请参阅 ASP.NET Core 中的 Razor 文件编译

通过多目标迁移库

库通常需要支持 ASP.NET Core 的多个版本。 针对以前版本的 ASP.NET Core 编译的大多数库应继续正常运行。 以下条件要求对应用进行交叉编译:

  • 库依赖于具有二进制重大更改的功能。
  • 库需要利用 ASP.NET Core 3.0 中的新增功能。

例如:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netcoreapp3.0;netstandard2.0</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
    <PackageReference Include="Microsoft.AspNetCore" Version="2.1.0" />
  </ItemGroup>
</Project>

使用 #ifdefs 来启用 ASP.NET Core 3.0 特定的 Api:

var webRootFileProvider =
#if NETCOREAPP3_0
    GetRequiredService<IWebHostEnvironment>().WebRootFileProvider;
#elif NETSTANDARD2_0
    GetRequiredService<IHostingEnvironment>().WebRootFileProvider;
#else
#error unknown target framework
#endif

有关在类库中使用 ASP.NET Core Api 的详细信息,请参阅 使用类库中的 ASP.NET Core API

其他更改

.NET Core 3.0 和更高版本中的验证系统将不可为 null 的参数或绑定属性视为具有 [Required] 特性。 有关详细信息,请参阅[必需] 特性

发布

删除项目目录中的binobj文件夹。

TestServer

对于直接使用TestServer 的应用,请在ConfigureWebHost中的 IWebHostBuilder 上创建 TestServer

[Fact]
public async Task GenericCreateAndStartHost_GetTestServer()
{
    using var host = await new HostBuilder()
        .ConfigureWebHost(webBuilder =>
        {
            webBuilder
                .UseTestServer()
                .Configure(app => { });
        })
    .StartAsync();

    var response = await host.GetTestServer().CreateClient().GetAsync("/");

    Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}

中断 API 更改

查看重大更改:

Azure App Service 上的 .NET Core 3.0

有关将 .NET Core 部署到 Azure App Service 的进度,请参阅应用服务网站上的官方 .Net core 在 Azure App Service 中提供 .NET Core 3.0 之前,请按照将ASP.NET Core 预览版部署到 Azure App Service中的说明进行操作。

上一篇:从 ASP.NET Core 3.0 迁移到 3.1

下一篇:从 ASP.NET Core 2.1 迁移到 2.2

关注微信小程序
程序员编程王-随时随地学编程

扫描二维码
程序员编程王

扫一扫关注最新编程教程