本文基於 2019/9/24 剛剛發佈的 ASP.NET Core 3.0 正式版,全文翻譯自微軟官方文檔英文版 "What's new in ASP.NET Core 3.0" 。 重點介紹了 ASP.NET Core 3.0 中最重要的更改,並提供相關文檔的連接。 由於官方文檔目前只有英文版... ...
目錄
- ASP.NET Core 3.0 的新增功能
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。
有關更多信息,請參見以下文章:
HttpContext 上的管道
現在可以使用 System.IO.Pipelines API 讀取請求正文並寫入響應正文。HttpRequest.BodyReader
屬性提供了一個 PipeReader,可以用於讀取請求正文;HttpResponse.BodyWriter
屬性提供了一個 PipeWriter,可以用於寫入響應正文。HttpRequest.BodyReader
是 HttpRequest.Body
流的相似物; HttpResponse.BodyWriter
是 HttpResponse.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 中的更改初探。