1. 程式人生 > >[翻譯] ASP.NET Core 3.0 的新增功能

[翻譯] ASP.NET Core 3.0 的新增功能

目錄

  • ASP.NET Core 3.0 的新增功能
    • Blazor
      • Blazor Server
      • Blazor WebAssembly (預覽)
      • Razor 元件
    • gRPC
    • SignalR
      • 新的 JSON 序列化
    • 新的 Razor 指令
    • 證書與 Kerberos 身份驗證
    • 模板變更
    • 通用主機
      • 主機配置
      • Startup 建構函式注入的更改
    • Kestrel
    • 預設啟用 HTTP/2
    • 請求計數器
    • 終結點路由
    • 執行狀況檢查
    • HttpContext 上的管道
    • IIS 中改進了的錯誤報告
    • 服務角色服務和輔助角色 SDK
    • Forwarded 標頭中介軟體的改進
    • 效能提升
    • ASP.NET Core 3.0 僅可在 .NET Core 3.0 上執行
    • 使用 ASP.NET Core 共享框架
    • 從 ASP.NET Core 共享框架中移除的程式集

ASP.NET Core 3.0 的新增功能

全文翻譯自微軟官方文件英文版 What's new in ASP.NET Core 3.0

本文重點介紹了 ASP.NET Core 3.0 中最重要的更改,並提供相關文件的連線。

Blazor

Blazor 是 ASP.NET Core 中的一個新的框架,用於使用 .NET 構建互動式的客戶端 Web UI:

  • 使用 C# 而不是 JavaScript 建立豐富的互動式 UI。
  • 共享用 .NET 編寫的伺服器端和客戶端應用程式邏輯。
  • 將 UI 渲染為 HTML 和 CSS,以提供廣泛的瀏覽器支援,包括移動瀏覽器。

Blazor 框架支援的場景:

  • 可重用的 UI 元件(Razor 元件)
  • 客戶端路由
  • 元件佈局
  • 對依賴注入的支援
  • 表單與驗證
  • 使用 Razor 類庫構建元件庫
  • JavaScript 互操作

有關更多資訊,請參閱:ASP.NET Core 中的 Blazor 簡介。

Blazor Server

Blazor 將元件渲染邏輯與 UI 更新的邏輯進行了解耦。Blazor Server 支援在伺服器上的 ASP.NET Core 應用程式中承載 Razor 元件。UI 的更新通過一個 SignalR 連線進行處理。Blazor Server 在 ASP.NET Core 3.0 中受支援。

Blazor WebAssembly (預覽)

Blazor 應用程式也可以使用基於 WebAssembly 的 .NET 執行時直接在瀏覽器中執行。Blazor WebAssembly 在 ASP.NET Core 3.0 中處於預覽狀態,且不受支援。未來的 ASP.NET Core 版本將支援 Blazor WebAssembly。

Razor 元件

Blazor 應用程式是由元件 (components) 構建而成的。元件是自包含的使用者介面元素,例如頁面、對話方塊或者表單等。元件是普通的 .NET 類,用於定義 UI 呈現邏輯和客戶端事件處理程式。您可以建立沒有 JavaScript 的富互動式 Web 應用程式。

Blazor 中的元件通常使用 Razor 語法編寫,它是 HTML 和 C# 的自然融合。Razor 元件與 Razor Pages(頁面)和 MVC 檢視 (view) 相似,因為它們都使用 Razor。與基於“請求-響應”模型的頁面與檢視不同,元件專門用於處理 UI 合成。

gRPC

gRPC:

  • 是一種流行的高效能 RPC(遠端過程呼叫)框架。
  • 為 API 開發提供了一種“契約優先“的方式。
  • 使用各種現代的技術,例如:
    • 通過 HTTP/2 傳輸
    • 使用 Protocol Buffers 作為介面描述語言
    • 二進位制序列化格式
  • 提供以下功能:
    • 身份驗證
    • 雙向的資料流與流程控制
    • 取消與超時

ASP.NET Core 3.0 中的 gRPC 功能包括:

  • Grpc.AspNetCore — 一個用於承載 gRPC 服務的 ASP.NET Core 框架。ASP.NET Core 上的 gRPC 能夠與日誌記錄、依賴注入 (DI) 身份驗證和授權等標準的 ASP.NET Core 功能整合在一起。
  • Grpc.Net.Client — 一個面向 .NET Core,構建在 HttpClient 上的 gRPC 客戶端。
  • Grpc.Net.ClientFactory — 用於將 gRPC 客戶端與 HttpClientFactory 整合。

有關更多資訊,參見:ASP.NET Core 上 gRPC 的簡介

SignalR

請參見更新 Signal 程式碼以獲取遷移說明。SignalR 現在使用 System.Text.Json 來序列化/反序列化 JSON 訊息。有關還原為基於 Newtonsoft.Json 的序列化程式的說明,請參閱切換到 Newtonsoft.Json。

在 SignalR 的 JavaScript 和 .NET 客戶端中,添加了對自動重新連線的支援。預設情況下,客戶端嘗試自動重新連線,並在 2, 10 和 30 秒後(如有必要)重試。如果客戶端成功重新連線,它將受到一個新的連線 ID。自動重新連線是選擇性加入的:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chatHub")
    .withAutomaticReconnect()
    .build();

可以通過傳遞基於毫秒的持續時間陣列來指定重新連線間隔:

.withAutomaticReconnect([0, 3000, 5000, 10000, 15000, 30000])
//.withAutomaticReconnect([0, 2000, 10000, 30000]) 預設時間間隔

可以傳入自定義實現以完全控制重新連線間隔。

如果在上次重新連線間隔之後重新連線失敗,則:

  • 客戶端認為連線已離線。
  • 客戶端停止嘗試重新連線。

為了在連線中斷時提供 UI 反饋,SignalR 客戶端 API 已擴充套件為包括以下事件處理程式:

  • onreconnecting: 為開發人員提供了禁用 UI 或告知使用者該應用程式處於離線狀態的機會。
  • onreconnected: 重新建立連線後,使開發人員有機會更新 UI。

以下程式碼在嘗試連線時使用 onreconnecting 更新 UI:

connection.onreconnecting((error) => {
    const status = `Connection lost due to error "${error}". Reconnecting.`;
    document.getElementById("messageInput").disabled = true;
    document.getElementById("sendButton").disabled = true;
    document.getElementById("connectionStatus").innerText = status;
});

以下程式碼在連線恢復時使用 onreconnected 更新 UI:

connection.onreconnected((connectionId) => {
    const status = `Connection reestablished. Connected.`;
    document.getElementById("messageInput").disabled = false;
    document.getElementById("sendButton").disabled = false;
    document.getElementById("connectionStatus").innerText = status;
});

當 hub 方法需要授權時,SignalR 3.0 及更高版本為授權處理程式提供自定義資源。該資源是 HubInvocationContext 的例項。HubInvocationContext 包括:

  • HubCallerContext
  • 正在呼叫的 hub 方法的名稱。
  • hub 方法的引數。

考慮以下聊天室應用程式示例,該應用程式允許通過 Azure Active Directory 進行多個組織登入。 具有 Microsoft 賬戶的任何人都可以登入聊天,但只有所屬組織的成員可以禁止使用者或檢視使用者的聊天記錄。 該應用可以限制特定使用者的某些功能。

public class DomainRestrictedRequirement :
    AuthorizationHandler<DomainRestrictedRequirement, HubInvocationContext>,
    IAuthorizationRequirement
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        DomainRestrictedRequirement requirement,
        HubInvocationContext resource)
    {
        if (context.User?.Identity?.Name == null)
        {
            return Task.CompletedTask;
        }

        if (IsUserAllowedToDoThis(
                resource.HubMethodName,
                context.User.Identity.Name))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }

    private bool IsUserAllowedToDoThis(string hubMethodName, string currentUsername)
    {
        if (hubMethodName.Equals("banUser",
            StringComparison.OrdinalIgnoreCase))
        {
            return currentUsername.Equals(
                "[email protected]",
                StringComparison.OrdinalIgnoreCase);
        }

        return currentUsername.EndsWith(
                "@jabbr.net",
                StringComparison.OrdinalIgnoreCase));
    }
}

在前面的程式碼中,DomainRestrictedRequirement 用作自定義 IAuthorizationRequirement。由於傳遞了 HubInvocationContext 資源,因此內部邏輯可以:

  • 檢查正在呼叫 hub 的上下文。
  • 決定是否允許使用者執行特定的 hub 方法。

可以使用策略名稱來修飾各個 hub 方法,程式碼會在執行時進行檢查。當客戶端嘗試呼叫各個 hub 方法時,DomainRestrictedRequirement 處理程式將會執行並控制對方法的訪問。基於 DomainRestrictedRequirement 控制訪問的方式:

  • 所有已登入使用者都可以呼叫 SendMessage 方法。
  • 只有使用 @jabbr.net 電子郵件地址登入的使用者才能檢視使用者的歷史記錄。
  • 只有 [email protected] 可以禁止使用者進入聊天室。
[Authorize]
public class ChatHub : Hub
{
    public void SendMessage(string message)
    {
    }

    [Authorize("DomainRestricted")]
    public void BanUser(string username)
    {
    }

    [Authorize("DomainRestricted")]
    public void ViewUserHistory(string username)
    {
    }
}

建立 DomainRestricted 策略可能涉及:

  • Startup.cs 中新增新策略。
  • 將自定義的 DomainRestrictedRequirement 需求作為引數提供。
  • 使用授權中介軟體註冊 DomainRestricted
services
    .AddAuthorization(options =>
    {
        options.AddPolicy("DomainRestricted", policy =>
        {
            policy.Requirements.Add(new DomainRestrictedRequirement());
        });
    });

SignalR hub 使用終結點路由. SignalR hub 連線先前已顯式地完成:

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

在以前的版本中,開發人員需要在各個不同的位置啟用控制器、Razor 頁面和 SignalR hub。顯式的連線導致一系列幾乎相同的路由片段:

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

app.UseRouting(routes =>
{
    routes.MapRazorPages();
});

SignalR 3.0 hub 可以通過終結點路由進行路由。使用終結點路由,通常可以在 UseRouting 中配置所有的路由:

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

ASP.NET Core 3.0 SignalR 添加了:

客戶端到伺服器的流。通過客戶端到伺服器的流傳輸,伺服器端方法可以採用 IAsyncEnumerable<T> 或者 ChannelReader<T> 的例項。在以下 C# 例項中,hub 上的 UploadStream 方法將從客戶端接收字串流:

public async Task UploadStream(IAsyncEnumerable<string> stream)
{
    await foreach (var item in stream)
    {
        // 處理流中的內容
    }
}

.NET 客戶端應用程式可以將一個 IAsyncEnumerable<T> 或者 ChannelReader<T> 的例項作為上述 UploadStream hub 方法的 stream 引數進行傳遞。

for 迴圈完成,且本地函式退出之後,將流完成傳送(After the for loop has completed and the local function exits, the stream completion is sent):

async IAsyncEnumerable<string> clientStreamData()
{
    for (var i = 0; i < 5; i++)
    {
        var data = await FetchSomeData();
        yield return data;
    }
}

await connection.SendAsync("UploadStream", clientStreamData());

JavaScript 客戶端應用將 SignalR Subject (或者一個 RxJS Subject) 用於上述 UploadStream hub 方法的 stream 引數。

let subject = new signalR.Subject();
await connection.send("StartStream", "MyAsciiArtStream", subject);

當 JavaScript 程式碼捕獲到字串並準備將其傳送到伺服器時,它可以使用 subject.next 方法來處理字串。

subject.next("example");
subject.complete();

使用類似前面兩個程式碼段的程式碼,可以建立實時流式傳輸體驗。

新的 JSON 序列化

現在預設情況下,ASP.NET Core 3.0 使用 System.Text.Json 進行 JSON 序列化:

  • 非同步讀取和寫入 JSON。
  • 針對 UTF-8 文字進行了優化。
  • 通常會比 Newtonsoft.Json 具有更高的效能。

要將 Json.NET 新增到 ASP.NET Core 3.0 請參閱新增基於 Newtonsoft.Json 的 JSON 格式支援。

新的 Razor 指令

以下列表包含了新的 Razor 指令:

  • @attribute — @attribute 指令將給定屬性應用於生成頁面或者檢視的類。例如:@attribute [Authorize]
  • @implements — @implements 指令為生成的類實現一個介面。例如:@implements IDisposable

證書與 Kerberos 身份驗證

證書身份驗證要求:

  • 配置伺服器以接收證書。
  • Startup.Configure 中新增身份驗證中介軟體。
  • Startup.ConfigureServices 中新增證書身份驗證服務。
public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(
        CertificateAuthenticationDefaults.AuthenticationScheme)
            .AddCertificate();
    // 其他服務配置已移除。
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseAuthentication();
    // 其他應用配置已移除。
}

證書身份驗證的選項 (Options) 提供以下功能:

  • 接受自簽名證書。
  • 檢查證書吊銷。
  • 檢查提供的證書是否具有正確的使用標誌。

預設的使用者主體 (user principal) 是根據證書屬性構建的。使用者主體包含一個事件。通過相應該事件,可以補充或者替換該主體。有關更多資訊,請參見在 ASP.NET Core 中配置證書身份驗證。

Windows 身份驗證 已擴充套件到了 Linux 和 macOS 上。在以前的版本中,Windows 身份驗證僅限於 IIS 和 HttpSys。在 ASP.NET Core 3.0 中,Kestrel 能夠在 Windows, Linux 和 macOS 上為加入了 Windows 域的主機使用 Negotiate(協商), Kerberos 和 NTLM。Kestrel 對這些身份驗證架構的支援由 Microsoft.AspNetCore.Authentication.Negotiate NuGet 包提供。與其他身份驗證服務一樣,在用用程式範圍內配置身份驗證,然後配置服務:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
        .AddNegotiate();
    // 其他服務配置已移除。
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseAuthentication();
    // 其他應用配置已移除。
}

主機要求:

  • Windows 主機必須將服務主體名稱 (SPN) 新增到承載該應用程式的使用者賬戶中。
  • Linux 和 macOS 主機必須加入域。
    • 必須為 Web 程序建立 SPN。
    • 必須在主機上生成和配置金鑰表文件。

有關更多資訊,請參見在 ASP.NET Core 中配置 Windows 身份驗證。

模板變更

Web UI 模板(Razor Pages, 帶有控制器和檢視的 MVC)已刪除以下內容:

  • “Cookie 同意” UI 不再包含在內。若要在 ASP.NET Core 3.0 模板生成的應用程式中啟用“Cookie 同意”功能,請參閱 ASP.NET Core 中的常規資料保護法規 (GDPR) 支援。
  • 現在,指令碼和相關的靜態資產被作為本地檔案引用,而不再使用 CDN。有關更多資訊,請參見指令碼和相關的靜態資產現在被作為本地檔案引用而不再使用 CDN (aspnet/AspNetCore.Docs #14350)。

Angular 模板已更新為使用 Angular 8。

預設情況下,Razor 類庫 (RCL) 模板預設為用於 Razor 元件開發。Visual Studio 中新的模板選項為頁面和檢視提供模板支援。在命令列中從模板建立 RCL 時,請傳入 -support-pages-and-views 選項 (dotnet new razorclasslib -support-pages-and-views)。

通用主機

ASP.NET Core 3.0 模板使用 .NET 通用主機。以前的版本使用 WebHostBuilder。使用 .NET Core 通用主機(HostBuilder),可以更好地將 ASP.NET Core 應用程式與其他非特定與 Web 的伺服器方案整合。有關更多資訊,請參見 HostBuilder 替換 WebHostBuilder。

主機配置

在釋出 ASP.NET Core 3.0 之前,帶有 ASPNETCORE_ 字首的環境變數會被載入,用於 Web 主機的主機配置。在 3.0 中,AddEvironmentVariables 用於載入帶有 DOTNET_ 以前追的環境變數,以使用 CreateDefaultBuilder 進行主機配置。

Startup 建構函式注入的更改

通用主機僅支援一下型別的 Startup 建構函式注入:

  • IHostEnvironment
  • IWebHostEnvironment
  • IConfiguration

仍然可以將所有服務以引數的形式直接注入 Startup.Configure 方法,參見 通用主機限制 Startup 建構函式注入 (aspnet/Announcements #353).

Kestrel

  • 為了遷移到通用主機,Kestrel 配置已更新。在 3.0 中,Kestrel 在 ConfigureWebHostDefaults 提供的 Web 主機構建器 (host builder) 上進行配置。
  • 連線介面卡 (Connection Adapter) 已從 Kestrel 中刪除,並由連線中介軟體代替 (Connection Middleware)。該中介軟體類似於 ASP.NET Core 管道中的 HTTP 中介軟體,但用於較低級別的連線。
  • Kestrel 傳輸層已在 Connections.Abstractions 中作為公共介面公開。
  • 標頭 (header) 和尾部 (trailer) 之間的歧義已通過將尾部標頭 (trailing header) 移動到新的集合來解決。
  • 同步 IO API(例如 HttpRequest.Body.Read)是引起執行緒飢餓進而導致程式崩潰的常見原因。在 3.0 中,預設情況下 AllowSynchronousIO 被禁用。

有關更多資訊,請參見Kestrel - 從 ASP.NET Core 2.2 遷移到 3.0。

預設啟用 HTTP/2

預設情況下,Kestrel 中為 HTTPS 端點啟用了 HTTP/2。當作業系統支援時,對 IIS 或者 HTTP.sys 的 HTTP/2 的支援將被啟用。

請求計數器

Hosting EventSource (Microsoft.AspNetCore.Hosting) 發出與傳入請求有關的以下 EventCounter:

  • requests-per-second
  • total-requests
  • current-requests
  • failed-requests

終結點路由

終結點路由得到了增強,該路由使各種框架(例如 MVC)可以與中介軟體更好地協同工作:

  • 中介軟體和終結點的順序可以在 Startup.Configure 的請求處理管道中進行配置。
  • 終結點和中介軟體與其他基於 ASP.NET Core 的技術(例如執行狀況檢查)進行良好的編排。
  • 終結點可以在中介軟體和 MVC 中實現各種策略,例如 CORS 或者授權等。
  • 過濾器和特性 (attribute) 可以被放置在控制器的方法上。

有關更多資訊,請參見 ASP.NET Core 中的路由。

執行狀況檢查

執行狀況檢查通過通用主機使用終結點路由。在 Startup.Configure 中,使用終結點 URL 或者相對路徑,在終結點構建器上呼叫 MapHealthChecks

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

執行狀況檢查終結點可以:

  • 指定一個或多個允許的主機/埠。
  • 要求授權。
  • 要求 CORS。

有關更多資訊,請參見以下文章:

  • 執行狀況檢查 - 從 ASP.NET Core 2.2 遷移到 3.0
  • ASP.NET Core 中的執行狀況檢查

HttpContext 上的管道

現在可以使用 System.IO.Pipelines API 讀取請求正文並寫入響應正文。HttpRequest.BodyReader 屬性提供了一個 PipeReader,可以用於讀取請求正文;HttpResponse.BodyWriter 屬性提供了一個 PipeWriter,可以用於寫入響應正文。HttpRequest.BodyReaderHttpRequest.Body 流的相似物; HttpResponse.BodyWriterHttpResponse.Body 流的相似物。

IIS 中改進了的錯誤報告

現在,在 IIS 中託管 ASP.NET Core 應用程式時的啟動錯誤會生成更豐富的診斷資料。這些錯誤會在適用的情況下使用堆疊跟蹤,報告給 Windows 事件日誌。此外,所有的警告、錯誤和未處理的異常,都會記錄到 Windows 事件日誌中。

服務角色服務和輔助角色 SDK

.NET Core 3.0 引入了新的輔助角色服務 (Worker Service) 應用模板。該模板是在 .NET Core 中編寫長時間執行的服務的起點。

有關更多資訊,請參見:

  • 作為 Windows 服務執行的 .NET Core 輔助角色 (.NET Core Workers as Windows Services)
  • 在 ASP.NET Core 中使用託管服務實現後臺任務
  • 在 Windows 服務中承載 ASP.NET Core

Forwarded 標頭中介軟體的改進

在早期版本的 ASP.NET Core 中,應用在部署到 Azure Linux 或者除 IIS 之外的任何反向代理之後,呼叫 UseHsts 和 UseHttpsRedirection 都是有問題的。轉發 Linux 和非 IIS 反向代理的方案中介紹了以前版本的修復方式。

此場景已在 ASP.NET Core 3.0 中修復。當 ASPNETCORE_FORWARDEDHEADERS_ENABLED 環境變數設定為 true 時,主機將啟用 Forwarded 標頭中介軟體。在 ASP.NET Core 的容器映象中,ASPNETCORE_FORWARDEDHEADERS_ENABLED 已被設定為 true

效能提升

ASP.NET Core 3.0 包括許多改進,可以減少記憶體使用並提高吞吐量:

  • 在將內建的依賴注入容器用於 scoped 服務時,減少記憶體的使用量。
  • 減少整個框架的記憶體分配,包括中介軟體的各類場景和路由。
  • 減少 WebSocket 連線的記憶體使用量。
  • 減少 HTTPS 連線的記憶體使用量,並提高吞吐量。
  • 新的、經過優化的、完全非同步的 JSON 序列化器。
  • 減少表單 (form) 解析的記憶體使用量,並提高吞吐量。

ASP.NET Core 3.0 僅可在 .NET Core 3.0 上執行

從 ASP.NET Core 3.0開始,.NET Framework 不再是受支援的目標框架。以 .NET Framework 為目標的專案可以繼續通過使用 .NET Core 2.1 LTS 版本在完全受支援的狀態下執行。絕大多數與 ASP.NET Core 2.1.x 相關的軟體包,都將在 .NET Core 2.1 的三年長期支援期內獲得支援。(Most ASP.NET Core 2.1.x related packages will be supported indefinitely, beyond the 3 year LTS period for .NET Core 2.1.)

有關遷移的更多資訊,請參見 將程式碼從 .NET Framework 移植到 .NET Core。

使用 ASP.NET Core 共享框架

Microsoft.AspNetCore.App 元包中包含的 ASP.NET Core 3.0 共享框架 (shared framework) 不再需要專案檔案中的顯式 <PackageReference /> 元素。在專案檔案中使用 Microsoft.NET.Sdk.Web SDK 時,將自動引用共享框架:

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

從 ASP.NET Core 共享框架中移除的程式集

從 ASP.NET Core 3.0 共享程式集中移除的最值得注意的程式集是:

  • Newtonsoft.Json (Json.NET)。要將 Json.NET 新增到 ASP.NET Core 3.0,請參閱 新增基於 Newtonsoft.Json 的 JSON 格式支援。ASP.NET Core 3.0 引入了 System.Text.Json 來讀寫 JSON。有關更多資訊,請參閱本文件中新的 JSON 序列化。
  • Entity Framework Core

有關共享框架中所移除程式集的完整列表,請參閱 從 Microsoft.AspNetCore.App 3.0 中移除的程式集。有關進行此修改的動機,更多資訊請參閱Microsoft.AspNetCore.App 在 3.0 中的破壞性變更 和 ASP.NET Core 3.0 中的更改初探。