從 ASP.NET Core 2.2 移轉到 3.0

作者:Scott AddieRick Anderson

本文說明如何將現有的 ASP.NET Core 2.2 專案更新為 ASP.NET Core 3.0。 建立新的 ASP.NET Core 3.0 專案可能有助於:

  • 與 ASP.NET Core 2.2 程式碼比較。
  • 將相關變更複製到您的 ASP.NET Core 3.0 專案。

必要條件

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

如果您的解決方案依賴 global.json 檔案而以特定的 .NET Core SDK 版本為目標,請將其 version 屬性更新為您電腦上安裝的 3.0 版:

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

更新專案檔

更新目標 Framework

ASP.NET Core 3.0 及更新版本只能在 .NET Core 上執行。 請將 目標 Framework Moniker (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
  • Microsoft.AspNetCore.SignalR
  • Microsoft.AspNetCore.SignalR.Core
  • Microsoft.AspNetCore.StaticFiles
  • Microsoft.AspNetCore.WebSockets
  • Microsoft.AspNetCore.WebUtilities
  • Microsoft.Net.Http.Headers

檢閱中斷性變更

檢閱中斷性變更

架構參考

透過上述其中一個套件提供的 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 執行時間且只存在於 Docker 映射上的 dotnet/core/aspnet 共享架構。 3.0 SDK 會使用 ASP.NET Core 來減少架構相依組建的大小,方法是不包含共用架構中可用的程式庫複本。 這是最多 18 MB 的潛在節省,但是需要 ASP.NET Core 執行階段存在/安裝才能執行應用程式。

若要判斷應用程式在 ASP.NET Core 共用架構上是否具有相依性 (直接或間接),請檢查應用程式建置/發佈期間產生的 runtimeconfig.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 版:

shared framework assemblies comparison

若要繼續使用已移除組件所提供的功能,請參考對應套件的 3.0 版本:

啟動變更

下圖顯示 ASP.NET Core 2.2 Razor Pages Web 應用程式中已刪除和已變更的行:

the deleted and changed lines in an ASP.NET Core 2.2 Razor Web app

在上圖中,已刪除的程式碼會以紅色顯示。 已刪除的程式碼不會顯示 cookie 選項程式碼,在比較檔案之前已刪除。

下圖顯示 ASP.NET Core 3.0 Razor Pages Web 應用程式中已新增和已變更的行:

the added and changed lines in an ASP.NET Core 3.0 Razor Web app

在上圖中,新增的程式碼會以綠色顯示。 如需下列變更的詳細資訊:

分析器支援

Microsoft.NET.Sdk.Web 為目標的專案,會隱含地參考先前隨附於 Microsoft.AspNetCore.Mvc.Analyzers 套件的分析器。 不需要其他參考就能啟用這些參考。

如果您的應用程式使用先前隨附於 Microsoft.AspNetCore.Mvc.Api.Analyzers 套件的 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 或更新版本中預設為內含式裝載模型。 如果專案檔中 <AspNetCoreHostingModel> 屬性的值為 InProcess,您可以選擇性地將其移除。

Kestrel

組態

將 Kestrel 組態移轉至由 ConfigureWebHostDefaults (Program.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>();
        });

如果應用程式以手動方式透過 ConfigureWebHost 建立主機,而不是使用 ConfigureWebHostDefaults,請在 Web 主機建立器上呼叫 UseKestrel

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

    host.Run();
}

連線中介軟體會取代連線配接器

連線配接器 (Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal.IConnectionAdapter) 已從 Kestrel 中移除。 以連線中介軟體取代連線配接器。 連線中介軟體類似於 ASP.NET Core 管線中的 HTTP 中介軟體,但是適用於較低層級的連線。 HTTPS 和連線記錄:

  • 已從連線配接器移至連線中介軟體。
  • 這些擴充方法可在舊版 ASP.NET Core 中運作。

如需詳細資訊,請參閱 Kestrel 文章中 ListenOptions.Protocols 一節中的 TlsFilterConnectionHandler 範例

已移動並公開傳輸抽象概念

Kestrel 傳輸層已公開為 Connections.Abstractions 中的公用介面。 作為這些更新的一部分:

  • 已移除 Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions 和相關聯型別。
  • NoDelay 已從 ListenOptions 移至傳輸選項。
  • Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal.SchedulingMode 已從 KestrelServerOptions 移除。

如需詳細資訊,請參閱下列 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 啟用或停用同步 I/O API,例如 HttpRequest.Body.ReadHttpResponse.Body.WriteStream.Flush。 這些 API 是導致應用程式當機的執行緒耗盡來源。 在 3.0 中,預設會停用 AllowSynchronousIO。 如需詳細資訊,請參閱 Kestrel文章中的同步 I/O 一節

如果需要同步 I/O,可以在所使用的伺服器上設定 AllowSynchronousIO 選項來啟用 (呼叫 ConfigureKestrel 時,例如若使用 Kestrel)。 請注意,伺服器 (Kestrel、HttpSys、TestServer 等等) 都有不會影響其他伺服器的 AllowSynchronousIO 選項。 您可以使用 IHttpBodyControlFeature.AllowSynchronousIO 選項,針對每個要求啟用所有伺服器的同步 I/O:

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

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

如果您在 Dispose 中呼叫同步 API 的 TextWriter 實作或其他資料流發生問題,請改為呼叫新的 DisposeAsync API。

如需詳細資訊,請參閱 [公告] 在所有伺服器中停用 AllowSynchronousIO (dotnet/AspNetCore #7644)

輸出格式器緩衝處理

Newtonsoft.JsonXmlSerializerDataContractSerializer 型輸出格式器僅支援同步序列化。 為了允許這些格式器使用伺服器的 AllowSynchronousIO 限制,MVC 會在寫入磁碟之前,緩衝這些格式器的輸出。 由於緩衝處理,MVC 會在使用這些格式器回應時包含 Content-Length 標頭。

System.Text.Json 支援非同步序列化,因此 System.Text.Json 型格式器不會緩衝處理。 請考慮使用此格式器來改善效能。

若要停用緩衝處理,應用程式可以在其啟動程序中設定 SuppressOutputFormatterBuffering

services.AddControllers(options => options.SuppressOutputFormatterBuffering = true)

請注意,如果未設定 AllowSynchronousIO,這可能會導致應用程式擲回執行階段例外狀況。

已移除 Microsoft.AspNetCore.Server.Kestrel.Https 組件

在 ASP.NET Core 2.1 中,Microsoft.AspNetCore.Server.Kestrel.Https.dll 的內容已移至 Microsoft.AspNetCore.Server.Kestrel.Core.dll。 這是使用 TypeForwardedTo 屬性的非中斷性更新。 針對 3.0,空白 Microsoft.AspNetCore.Server.Kestrel.Https.dll 組件和 NuGet 套件已移除。

參考 Microsoft.AspNetCore.Server.Kestrel.Https 的程式庫應該將 ASP.NET Core 相依性更新為 2.1 會更新版本。

以 ASP.NET Core 2.1 或更新版本為目標的應用程式或程式庫,應該移除對 Microsoft.AspNetCore.Server.Kestrel.Https 套件的任何直接參考。

Newtonsoft.Json (Json.NET) 支援

改善 ASP.NET Core 共用架構的過程中,Newtonsoft.Json (Json.NET) 已從 ASP.NET Core 共用架構移除。

適用於 ASP.NET Core 的預設 JSON 序列化程式現在是 System.Text.Json,這是 .NET Core 3.0 中的新功能。 請考慮盡可能使用 System.Text.Json。 它是高效能的,不需要額外的程式庫相依性。 不過,由於 System.Text.Json 是新功能,因此目前可能缺少您的應用程式所需的功能。 如需詳細資訊,請參閱如何從 Newtonsoft.Json 移轉至 System.Text.Json

在 ASP.NET Core 3.0 SignalR 專案中使用 Newtonsoft.Json

  • 安裝 Microsoft.AspNetCore.SignalR.Protocols.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

  • 安裝 Microsoft.AspNetCore.Mvc.NewtonsoftJson 套件。

  • 更新 Startup.ConfigureServices 以呼叫 AddNewtonsoftJson

    services.AddMvc()
        .AddNewtonsoftJson();
    

    AddNewtonsoftJson 與新 MVC 服務註冊方法相容:

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

    Newtonsoft.Json 設定可以在對 AddNewtonsoftJson 的呼叫中設定:

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

    注意:如果 AddNewtonsoftJson 方法無法使用,請確定您已安裝 Microsoft.AspNetCore.Mvc.NewtonsoftJson 套件。 常見錯誤是安裝 Newtonsoft.Json 套件,而不是 Microsoft.AspNetCore.Mvc.NewtonsoftJson 套件。

如需詳細資訊,請參閱新增 Newtonsoft.Json 型 JSON 格式支援

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,請在 UseRouting前面放置 UseStaticFiles

  • 如果應用程式使用例如 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],請在使用 CORS 的任何其他中介軟體前面放置對 UseCors 的呼叫 (例如,在 UseAuthenticationUseAuthorizationUseEndpoints 前面放置 UseCors)。

  • IWebHostEnvironment 取代 IHostingEnvironment,並且針對 Microsoft.AspNetCore.Hosting 命名空間新增 using 陳述式。

  • IApplicationLifetime 取代為 IHostApplicationLifetime (Microsoft.Extensions.Hosting 命名空間)。

  • EnvironmentName 取代為 Environments (Microsoft.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 的呼叫必須在對 UseRoutingUseEndpoints 的呼叫之間出現才能生效。

健康情況檢查

健康情況檢查會搭配一般主機使用端點路由。 在 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] 屬性可以用來在必要時覆寫預設原則。

在以下範例中:

  • CORS 會針對具有 default 具名原則的所有端點啟用。
  • 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 或更新版本中,UseAuthorization 是在 Startup.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()
    {
        ...
    }
}

使用端點路由時,建議您不要設定 AuthorizeFilter 並改為依賴授權中介軟體。 如果應用程式在 MVC 中使用 AuthorizeFilter 作為全域篩選,建議您重構程式碼,以在對 AddAuthorization 的呼叫中提供原則。

DefaultPolicy 一開始設定為需要驗證,因此不需要額外的設定。 在下列範例中,MVC 端點會標示為 RequireAuthorization,因此所有要求都必須根據 DefaultPolicy 獲得授權。 不過,由於 [AllowAnonymous],所以 HomeController 允許在沒有使用者登入應用程式的情況下存取:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

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

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

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

特定端點的授權

您也可以針對特定端點類別設定授權。 下列程式碼是轉換 MVC 應用程式的範例,將全域 AuthorizeFilter 設定為具有需要授權之特定原則的應用程式:

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]RequireAuthorizationFallbackPolicyDefaultPolicy 不同。 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 對應每個中樞。 如同舊版,會明確列出每個中樞。

在下列範例中,會新增 ChatHubSignalR 中樞的支援:

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 中,該選項現在只會控制在觀察到 backpressure 之前的大小上限。

共用架構中的 SignalR 組件

ASP.NET Core SignalR 伺服器端組件現在會隨 .NET Core SDK 一起安裝。 如需詳細資訊,請參閱本文件中的移除過時的套件參考

MVC 控制器

控制器的對應現在會在 UseEndpoints 內進行。

如果應用程式使用屬性路由,請新增 MapControllers。 由於在 ASP.NET Core 3.0 或更新版本中,路由包含許多架構的支援,因此新增屬性路由控制器是選擇性的。

取代下列項目:

  • 包含 MapControllerRouteMapRoute
  • 包含 MapAreaControllerRouteMapAreaRoute

由於路由現在包含不僅僅是 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?}");
    });
}

從控制器動作名稱移除非同步尾碼

在 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/ListAsync 路由存取。

  • 產生連結需要指定 Async 尾碼。 例如:

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

在 ASP.NET Core 3.0 中:

  • 上述動作可以在 Products/List 路由存取。

  • 連結產生不需要指定 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 Pages

對應 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

透過 UseMvcUseMvcWithDefaultRoute 在 ASP.NET Core 3.0 中使用 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 的優點是能夠套用授權,並更精細地控制比對原則。

在下列範例中,MapHealthChecks 會在 /healthz 呼叫健康情況檢查端點:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

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

HostBuilder 取代 WebHostBuilder

ASP.NET Core 3.0 範本會使用一般主機。 舊版使用 Web 主機。 下列程式碼顯示 ASP.NET Core 3.0 範本產生的 Program 類別:

// 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 已移至不同的組件

Microsoft.AspNetCore.Authorization.dll 中的 ASP.NET Core 2.2 和較低 AddAuthorization 方法:

  • 已重新命名 AddAuthorizationCore
  • 已移至 Microsoft.AspNetCore.Authorization.Policy.dll

使用 Microsoft.AspNetCore.Authorization.dllMicrosoft.AspNetCore.Authorization.Policy.dll 的應用程式不會受到影響。

未使用 Microsoft.AspNetCore.Authorization.Policy.dll 的應用程式應該執行下列其中一項作業:

  • 將參考新增至 Microsoft.AspNetCore.Authorization.Policy.dll。 此方法適用於大部分的應用程式,而且都是必要項目。
  • 切換為使用 AddAuthorizationCore

如需詳細資訊,請參閱 AddAuthorization(o =>) 多載中的中斷性變更位於不同組件 #386

Identity UI

ASP.NET Core 3.0 的 Identity UI 更新:

  • 將套件參考新增至 Microsoft.AspNetCore.Identity.UI
  • 不使用 Razor Pages 的應用程式必須呼叫 MapRazorPages。 請參閱本文件中的 Razor Pages
  • Bootstrap 4 是預設 UI 架構。 設定 IdentityUIFrameworkVersion 專案屬性以變更預設值。 如需詳細資訊,請參閱此 GitHub 公告

SignalR

SignalR JavaScript 用戶端已從 @aspnet/signalr 變更為 @microsoft/signalr。 若要回應這項變更,請變更 package.json 檔案、require 陳述式和 ECMAScript import 陳述式中的參考。

System.Text.Json 是預設通訊協定

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

如果您使用在 System.Text.Json 中不支援的 Newtonsoft.Json 功能,您可以切換回 Newtonsoft.Json。 請參閱本文中稍早的在 ASP.NET Core 3.0 SignalR 專案中使用 Newtonsoft.Json

Redis 分散式快取

Microsoft.Extensions.Caching.Redis 套件不適用於 ASP.NET Core 3.0 或更新版本應用程式。 將套件參考取代為 Microsoft.Extensions.Caching.StackExchangeRedis。 如需詳細資訊,請參閱 ASP.NET Core 中的分散式快取

加入執行階段編譯

在 ASP.NET Core 3.0 以前,檢視的執行階段編譯是架構的隱含功能。 執行階段編譯補充檢視的建置時間編譯。 可讓架構在修改檔案時編譯 Razor 檢視和頁面 (.cshtml 檔案),而不需要重建整個應用程式。 此功能支援在 IDE 中快速編輯和重新整理瀏覽器以檢視變更的案例。

在 ASP.NET Core 3.0 中,執行階段編譯是加入案例。 建置時間編譯是預設啟用之檢視編譯的唯一機制。 執行階段依賴 Visual Studio 或 Visual Studio Code 中的 dotnet-watch,在偵測到對 .cshtml 檔案的變更時重建專案。 在 Visual Studio 中,對專案中 .cs.cshtml.razor 檔案的變更會執行 (Ctrl+F5),但是未偵錯 (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/main/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 變更

檢閱中斷性變更:

使用 catch-all 參數的端點路由

警告

由於路由中的錯誤 (bug)catch-all 參數可能會錯誤比對路由。 受到此錯誤 (bug) 影響的應用程式具有下列特性:

  • catch-all 路由,例如 {**slug}"
  • catch-all 路由無法比對應該相符的要求。
  • 移除其他路由讓 catch-all 路由開始運作。

如需發生此錯誤 (bug) 的範例案例,請參閱 GitHub 錯誤 (bug) 1867716579

這個錯誤 (bug) 的加入修正包含在 .NET Core 3.1.301 SDK 和更新版本。 下列程式碼會設定修正此錯誤 (bug) 的內部參數:

public static void Main(string[] args)
{
   AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior", 
                         true);
   CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.

Azure App Service 上的 .NET Core 3.0

.NET Core 推出到 Azure App Service 已完成。 所有 Azure App Service 資料中心都可使用 .NET Core 3.0。

ASP.NET Core 模組 (ANCM)

如果在安裝 Visual Studio 時,ASP.NET Core 模組 (ANCM) 不是選取的元件,或者如果系統上已安裝舊版的 ANCM,請下載最新的 .NET Core 裝載套件組合安裝程式 (直接下載),並執行安裝程式。 如需詳細資訊,請參閱裝載組合套件