原文鏈接:https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-rc-1/[1]
原文作者:Daniel Roth
翻譯:沙漠盡頭的狼(谷歌翻譯加持)
.NET 7 Release Candidate 1 (RC1) 現已推出[2],其中包括對 ASP.NET Core 的許多重大新改進。
以下是此預覽版中新增功能的摘要:
Blazor WebAssembly 中的動態身份驗證請求
處理位置變化事件
Blazor WebAssembly 調試改進
.NET 6項目的.NET WebAssembly項目構建工具
WebAssembly 上的 .NET JavaScript 互操作
Kestrel 完整的證書鏈改進
更快的 HTTP/2 上傳
HTTP/3 改進
通過 HTTP/3 對 WebTransport 的實驗性 Kestrel 支持
對 gRPC JSON 轉碼的實驗性 OpenAPI 支持
速率限制中間件改進
macOS 開發證書改進
有關為 .NET 7 計劃的 ASP.NET Core 工作的更多詳細信息,請參閱GitHub 上的 .NET 7 的完整 ASP.NET Core 路線圖[3]。
開始使用
要開始使用 .NET 7 Release Candidate 1 中的 ASP.NET Core,請安裝 .NET 7 SDK[4]。
如果你在 Windows 上使用 Visual Studio,我們建議安裝最新的Visual Studio 2022 預覽版[5]。如果您使用的是 macOS,我們建議您安裝最新的Visual Studio 2022 for Mac 預覽版[6]。
要安裝最新的 .NET WebAssembly 構建工具,請從提升的命令提示符處運行以下命令:
dotnet?workload?install?wasm-tools
升級現有項目
要將現有的 ASP.NET Core 應用從 .NET 7 Preview 7 升級到 .NET 7 RC1:
將所有 Microsoft.AspNetCore.* 包引用更新為
.7.0.0-rc.1.*
將所有 Microsoft.Extensions.* 包引用更新為
.7.0.0-rc.1.*
另請參閱.NET 7 的 ASP.NET Core中的重大更改[7]的完整列表。
Blazor WebAssembly 中的動態身份驗證請求
Blazor 為使用 OpenID Connect 和各種身份提供程序(包括 Azure Active Directory (Azure AD) 和 Azure AD B2C)的身份驗證提供開箱即用的支持。在 .NET 7 中,Blazor 現在支持在運行時使用自定義參數創建動態身份驗證請求,以處理 Blazor WebAssembly 應用中更高級的身份驗證方案。要指定其他參數,請使用新的InteractiveRequestOptions
類型和NavigateToLogin``輔助方法NavigationManager
。
例如,您可以為身份提供者指定一個登錄提示,以便像這樣進行身份驗證:
InteractiveRequestOptions?requestOptions?=?new()
{Interaction?=?InteractionType.SignIn,ReturnUrl?=?NavigationManager.Uri,
};
requestOptions.TryAddAdditionalParameter("login_hint",?"user@example.com");
NavigationManager.NavigateToLogin("authentication/login",?requestOptions);
同樣,您可以指定 OpenID Connect prompt
參數,例如當您想要強制交互式登錄時:
InteractiveRequestOptions?requestOptions?=?new()
{Interaction?=?InteractionType.SignIn,ReturnUrl?=?NavigationManager.Uri,
};
requestOptions.TryAddAdditionalParameter("prompt",?"login");
NavigationManager.NavigateToLogin("authentication/login",?requestOptions);
您可以使用IAccessTokenProvider
直接用于請求令牌時指定這些選項:
var?accessTokenResult?=?await?AccessTokenProvider.RequestAccessToken(new?AccessTokenRequestOptions{Scopes?=?new[]?{?"SecondAPI"?}});if?(!accessTokenResult.TryGetToken(out?var?token))
{accessTokenResult.InteractiveOptions.AddAdditionalParameter("login_hint",?"user@example.com");NavigationManager.NavigateToLogin(accessTokenResult.InteractiveRequestUrl,?accessTokenResult.InteractionOptions);
}
當無法獲取令牌時,您還可以通過AuthorizationMessageHandler
指定身份驗證請求選項:
try
{await?httpclient.Get("/orders");}
catch?(AccessTokenNotAvailableException?ex)
{ex.Redirect(requestOptions?=>{requestOptions.AddAdditionalParameter("login_hint",?"user@example.com");});
}
為身份驗證請求指定的任何其他參數都將傳遞到底層身份驗證庫,然后由其處理。
注意:為msal.js指定附加參數尚未完全實現,但預計將在即將發布的版本中完成。
處理位置變化事件
.NET 7 中的 Blazor 現在支持處理位置更改事件。這允許您在用戶執行頁面導航時警告用戶未保存的工作或執行相關操作。
使用NavigationManager
服務的RegisterLocationChangingHandler
方法注冊處理程序用于處理位置更改事件。然后,您的處理程序可以在導航時執行異步工作,或者通過調用LocationChangingContext
的PreventNavigation
取消導航。RegisterLocationChangingHandler
返回一個IDisposable
實例,該實例在釋放時會刪除相應的位置更改處理程序。
例如,以下處理程序阻止導航到計數器頁面:
var?registration?=?NavigationManager.RegisterLocationChangingHandler(async?context?=>
{if?(context.TargetLocation.EndsWith("counter")){context.PreventNavigation();}
});
請注意,您的處理程序只會被用于應用程序內的內部導航調用。外部導航只能使用JavaScript 中的beforeunload
事件同步處理。
新NavigationLock
組件使處理位置變化事件的常見場景更容易。NavigationLock
公開一個OnBeforeInternalNavigation
回調,您可以使用它來攔截和處理內部位置更改事件。如果您希望用戶也確認外部導航,您可以使用該ConfirmExternalNavigations
屬性,它將攔截beforeunload
事件并觸發瀏覽器特定提示。
<EditForm?EditContext="editContext"?OnValidSubmit="Submit">...
</EditForm>
<NavigationLock?OnBeforeInternalNavigation="ConfirmNavigation"?ConfirmExternalNavigation?/>@code?{private?readonly?EditContext?editContext;...//?Called?only?for?internal?navigations//?External?navigations?will?trigger?a?browser?specific?promptasync?Task?ConfirmNavigation(LocationChangingContext?context){if?(editContext.IsModified()){var?isConfirmed?=?await?JS.InvokeAsync<bool>("window.confirm",?"Are?you?sure?you?want?to?leave?this?page?");if?(!isConfirmed){context.PreventNavigation();}}}
}
Blazor WebAssembly 調試改進
.NET 7 中的 Blazor WebAssembly 調試現在具有以下改進:
支持 Just My Code 設置以顯示或隱藏不在用戶代碼中的類型成員
支持檢查多維數組
調用堆棧現在顯示異步方法的正確名稱
改進的表達式評估
正確處理派生成員的
new
關鍵字在
System.Diagnostics
中支持調試器相關的屬性
為.NET 6項目的.NET WebAssembly 構建工具
現在,在使用 .NET 7 SDK 時,您可以將 .NET WebAssembly 構建工具用于 .NET 6 項目。新的wasm-tools-net6
工作負載包括用于 .NET 6 項目的 .NET WebAssembly 構建工具,以便它們可以與 .NET 7 SDK 一起使用。要安裝新wasm-tools-net6
工作負載,請從提升的命令提示符運行以下命令:
dotnet?workload?install?wasm-tools-net6
安裝 .NET WebAssembly 構建工具帶來的wasm-tools
工作負載是為 .NET 7 項目準備的(翻譯有點拗口,這句可能翻譯錯了,原文是:The existing wasm-tools workload installs the .NET WebAssembly build tools for .NET 7 projects.)。但是,.NET 7 版本的 .NET WebAssembly 構建工具與使用 .NET 6 構建的現有項目不兼容。需要同時支持 .NET 6 和 .NET 7 使用 .NET WebAssembly 構建工具的項目將需要使用 multi-targeting。
WebAssembly 上的 .NET JavaScript 互操作
.NET 7 引入了一種新的低級(low-level)機制,用于在基于 JavaScript 的應用程序中使用 .NET。借助這一新的 JavaScript 互操作功能,您可以使用 .NET WebAssembly 運行時從 JavaScript 調用 .NET 代碼,也可以從 .NET 調用 JavaScript 功能,而無需依賴 Blazor UI 組件模型。
查看新的 JavaScript 互操作功能的最簡單方法是在wasm-experimental
工作負載中使用新的實驗模板:
dotnet?workload?install?wasm-experimental
此工作負載包含兩個項目模板:WebAssembly Browser App 和 WebAssembly Console App。這些模板是實驗性的,這意味著它們的開發人員工作流尚未完全整理好(例如,這些模板尚未在 Visual Studio 中運行)。但是 .NET 7 支持這些模板中使用的 .NET 和 JavaScript API,并為通過 JavaScript 在 WebAssembly 上使用 .NET 提供了基礎。
您可以通過運行以下命令來創建 WebAssembly 瀏覽器應用程序:
dotnet?new?wasmbrowser
此模板創建一個簡單的 Web 應用程序,演示如何在瀏覽器中同時使用 .NET 和 JavaScript。WebAssembly 控制臺應用程序類似,但作為 Node.js 控制臺應用程序而不是基于瀏覽器的 Web 應用程序運行。
創建的示例項目中的main.js中的 JavaScript 模塊演示了如何從 JavaScript 運行 .NET 代碼。相關 API 是從dotnet.js導入的。這些 API 使您能夠設置可以導入到 C# 代碼中的命名模塊,以及調用 .NET 代碼公開的方法,包括Program.Main
:
import?{?dotnet?}?from?'./dotnet.js'const?is_browser?=?typeof?window?!=?"undefined";
if?(!is_browser)?throw?new?Error(`Expected?to?be?running?in?a?browser`);//?Setup?the?.NET?WebAssembly?runtime
const?{?setModuleImports,?getAssemblyExports,?getConfig,?runMainAndExit?}?=?await?dotnet.withDiagnosticTracing(false).withApplicationArgumentsFromQuery().create();//?Set?module?imports?that?can?be?called?from?.NET
setModuleImports("main.js",?{window:?{location:?{href:?()?=>?globalThis.window.location.href}}
});const?config?=?getConfig();
const?exports?=?await?getAssemblyExports(config.mainAssemblyName);
const?text?=?exports.MyClass.Greeting();?//?Call?into?.NET?from?JavaScript
console.log(text);document.getElementById("out").innerHTML?=?`${text}`;
await?runMainAndExit(config.mainAssemblyName,?["dotnet",?"is",?"great!"]);?//?Run?Program.Main
要導入 JavaScript 函數以便可以從 C# 調用它,請在匹配的方法簽名上使用新的JSImportAttribute
:
[JSImport("window.location.href",?"main.js")]
internal?static?partial?string?GetHRef();
JSImportAttribute
的第一個參數是要導入的 JavaScript 函數的名稱,第二個參數是模塊的名稱,這兩個參數都是由main.js中的setModuleImports
調用設置的。
在導入的方法簽名中,您可以對參數和返回值使用 .NET 類型,這些類型將為您編組。使用JSMarshalAsAttribute<T>
控制導入的方法參數的編組方式。例如,您可以選擇將一個long
編組為JSType.Number
或JSType.BigInt
。您可以將Action/Func
回調作為參數傳遞,這些參數將被編組為可調用的 JavaScript 函數。您可以同時傳遞 JavaScript 和托管對象引用,它們將被編組為代理對象,使對象在邊界上保持活動狀態,直到代理被垃圾回收。您還可以導入和導出帶Task
返回值的異步方法,它將作為 JavaScript promises進行編組。在導入和導出的方法上,大多數封裝類型作為參數和返回值雙向工作,。
使用JSExportAttribute
導出 .NET 方法以便可以從 JavaScript 調用:
[JSExport]
internal?static?string?Greeting()
{var?text?=?$"Hello,?World!?Greetings?from?{GetHRef()}";Console.WriteLine(text);return?text;
}
Blazor 提供了自己的基于IJSRuntime接口的 JavaScript 互操作機制,該機制在所有 Blazor 托管模型中得到統一支持。這種常見的異步抽象使庫作者能夠構建可在 Blazor 生態系統中共享的 JavaScript 互操作庫,并且仍然是在 Blazor 中執行 JavaScript 互操作的推薦方式。但是,在 Blazor WebAssembly 應用程序中,您還可以選擇IJSInProcessRuntime
進行同步JavaScript互操作調用,甚至使用IJSUnmarshalledRuntime
進行解組調用。IJSUnmarshalledRuntime
使用起來很棘手,僅部分支持。在 .NET 7 中IJSUnmarshalledRuntime
現在已經過時,應該用[JSImport]/[JSExport]機制替換。Blazor 不直接公開從 JavaScript 使用的dotnet
運行時實例,但仍然可以通過.getDotnetRuntime(0)
調用。您還可以通過在C#代碼中調用JSHost.ImportAsync
導入JavaScript模塊,這可以使模塊導出對 [JSImport]
可見。
Kestrel 完整的證書鏈改進
類型X509Certificate2Collection
的HttpsConnectionAdapterOptions
具有新屬性ServerCertificateChaintype
,通過允許指定包含中間證書的完整鏈,可以更輕松地驗證證書鏈。有關詳細信息,請參閱dotnet/aspnetcore#21513[8]。
更快的 HTTP/2 上傳
我們已將 Kestrel 的默認 HTTP/2 上傳連接窗口大小從 128 KB 增加到 1 MB,這顯著提高了使用 Kestrel 的默認配置的高延遲連接的 HTTP/2 上傳速度。
在僅引入 10 毫秒的人工延遲后,我們通過在 localhost 上使用單個流上傳 108 MB 文件上傳來測試增加此限制的影響,并看到上傳速度提高了大約 6 倍。
下面的屏幕截圖比較了在 Edge 的開發工具網絡選項卡中上傳 108 MB 所需的時間:

之前:26.9 秒
之后:4.3 秒
HTTP/3 改進
.NET 7 RC1 繼續改進 Kestrel 對 HTTP/3 的支持。改進的兩個主要領域是與 HTTP/1.1 和 HTTP/2 的功能對等以及性能。
此版本最大的特點是完全支持ListenOptions.UseHttps[9]使用HTTP/3。Kestrel 提供了用于配置連接證書的高級選項,例如攔截到Server Name Indication (SNI)[10]。
以下示例顯示如何使用 SNI 回調來解析 TLS 選項:
var?builder?=?WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options?=>
{options.ListenAnyIP(8080,?listenOptions?=>{listenOptions.Protocols?=?HttpProtocols.Http1AndHttp2AndHttp3;listenOptions.UseHttps(new?TlsHandshakeCallbackOptions{OnConnection?=?context?=>{var?options?=?new?SslServerAuthenticationOptions{ServerCertificate?=?ResolveCertForHost(context.ClientHelloInfo.ServerName)};return?new?ValueTask<SslServerAuthenticationOptions>(options);},});});
});
我們還做了大量工作來減少 .NET 7 RC1 中的 HTTP/3 分配。您可以在這里看到其中的一些改進:
HTTP/3: Avoid per-request cancellation token allocations[11]
HTTP/3: Avoid ConnectionAbortedException allocations[12]
HTTP/3: ValueTask pooling[13]
通過 HTTP/3 對 WebTransport 的實驗性 Kestrel 支持
我們很高興地宣布在 Kestrel 中對基于 HTTP/3 的 WebTransport 的內置實驗性支持。此功能是由我們優秀的實習生 Daniel 編寫的!WebTransport 對于類似于 WebSockets 的傳輸協議是一個新的草案規范[14],它允許每個連接使用多個流。這對于拆分通信通道并因此避免線頭阻塞很有用。例如,考慮一個基于網絡的在線游戲,其中游戲狀態在一個雙向流上傳輸,玩家對游戲語音聊天功能的語音在另一個雙向流上傳輸,而玩家的控制在單向流上傳輸。使用 WebSockets,這一切都需要放在單獨的連接上或壓縮到單個流中。使用 WebTransport,您可以將所有流量保留在一個連接上,但將它們分成自己的流,如果一個流阻塞,其他流將繼續不間斷。
其他詳細信息將在單獨的博客文章中提供。
對 gRPC JSON 轉碼的實驗性 OpenAPI 支持
gRPC JSON 轉碼[15]是 .NET 7 中的一項新功能,用于將 gRPC API 轉換為 RESTful API。
.NET 7 RC1 增加了從 gRPC 轉碼 RESTful API 生成 OpenAPI 的實驗性支持。帶有 gRPC JSON 轉碼的 OpenAPI 是一個非常需要的功能,我們很高興提供一種結合這些偉大技術的方法。NuGet 包在 .NET 7 中是實驗性的,讓我們有時間探索集成這些功能的最佳方式。
要使用 gRPC JSON 轉碼啟用 OpenAPI:
添加對Microsoft.AspNetCore.Grpc.Swagger[16]的包引用。版本必須為 0.3.0-xxx 或更高版本。
在啟動時配置 Swashbuckle。該
AddGrpcSwagger
方法將 Swashbuckle 配置為包含 gRPC 端點。
var?builder?=?WebApplication.CreateBuilder(args);
builder.Services.AddGrpc().AddJsonTranscoding();
builder.Services.AddGrpcSwagger();
builder.Services.AddSwaggerGen(c?=>
{c.SwaggerDoc("v1",new?OpenApiInfo?{?Title?=?"gRPC?transcoding",?Version?=?"v1"?});
});var?app?=?builder.Build();
app.UseSwagger();
app.UseSwaggerUI(c?=>
{c.SwaggerEndpoint("/swagger/v1/swagger.json",?"My?API?V1");
});
app.MapGrpcService<GreeterService>();app.Run();
要確認 Swashbuckle 正在為 RESTful gRPC 服務生成 Swagger,請啟動應用程序并導航到 Swagger UI 頁面:

限流中間件改進
我們為 .NET 7 RC1 中的限流中間件添加了許多功能,使其功能更強大,更易于使用。
我們添加了可用于啟用或禁用給定端點上的速率限制的屬性。例如,以下是如何將命名策略應用MyControllerPolicy
到控制器:
public?class?MyController?:?Controller
{[EnableRateLimitingAttribute("MyControllerPolicy")]public?IActionResult?Index(){return?View();}
}
您還可以在給定端點或一組端點上完全禁用速率限制。假設您在一組端點上啟用了速率限制:
app.MapGroup("/public/todos").RequireRateLimiting("MyGroupPolicy");
然后,您可以禁用該組中特定端點的速率限制,如下所示:
app.MapGroup("/public/todos/donothing").DisableRateLimiting();
您現在還可以將策略直接應用于端點。與命名策略不同,以這種方式添加的策略不需要在RateLimiterOptions
. 假設您已經定義了一個策略類型:
public?class?MyRateLimiterPolicy?:?IRateLimiterPolicy<string>
{
...
}
您可以將其實例直接添加到端點,如下所示:
app.MapGet("/",?()?=>?"Hello?World!").RequireRateLimiting(new?MyRateLimiterPolicy());
最后,我們更新了RateLimiterOptions
便捷方法以采用Action<Options>
而不是Options
實例,還添加了IServiceCollection
使用速率限制的擴展方法。因此,要在您的應用中啟用上述所有速率限制策略,您可以執行以下操作:
builder.Services.AddRateLimiter(options?=>
{options.AddTokenBucketLimiter("MyControllerPolicy",?options?=>{options.TokenLimit?=?1;options.QueueProcessingOrder?=?QueueProcessingOrder.OldestFirst;options.QueueLimit?=?1;options.ReplenishmentPeriod?=?TimeSpan.FromSeconds(10);options.TokensPerPeriod?=?1;}).AddPolicy<string>("MyGroupPolicy",?new?MyRateLimiterPolicy());
});
這會將 TokenBucketLimiter
應用于您的控制器,將您的自定義MyRateLimiterPolicy
應用于匹配端點./public/todos
(除了/public/todos/donothing
),并將您的自定義MyRateLimiterPolicy
應用于/
。
macOS 開發證書改進
在此版本中,我們對 macOS 用戶使用 HTTPS 開發證書的體驗進行了一些重大的質量改進,大大減少了在創建、信任、讀取和刪除 ASP.NET Core HTTPS 開發時顯示的身份驗證提示的證書。當 macOS 上的 ASP.NET Core 開發人員嘗試在其工作流程中使用開發證書時,這一直是一個痛點。
在此版本中,通過dotnet dev-certs
工具在 macOS 上生成的開發證書具有更窄的信任范圍,現在將設置添加到每個用戶的信任設置中而不是系統范圍內,并且 Kestrel 將能夠綁定到這些新證書而無需訪問系統鑰匙串。作為這項工作的一部分,還對質量進行了一些改進,例如重新處理一些面向用戶的消息以提高清晰度和準確性。
在 macOS 上的開發過程中使用 HTTPS 時,這些更改結合在一起可以帶來更流暢的體驗和更少的密碼提示。
查看新的 Blazor 更新的實際應用!
有關 Blazor WebAssembly 中的動態身份驗證請求、Blazor WebAssembly 調試改進以及 WebAssembly 上的 .NET JavaScript 互操作的實時演示,請參閱我們最近的Blazor 社區站會[17]:
視頻地址:https://www.youtube.com/watch?v=-ZSscIhQaRk&feature=emb_imp_woyt[18]
給予反饋
我們希望您喜歡 .NET 7 中的 ASP.NET Core 預覽版。通過在GitHub[19] 上提交問題,讓我們知道您對這些新改進的看法。
感謝您試用 ASP.NET Core!
參考資料
[1]
https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-rc-1/: https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-rc-1/
[2].NET 7 Release Candidate 1 (RC1) 現已推出: https://devblogs.microsoft.com/dotnet/announcing-dotnet-7-rc-1
[3].NET 7 的完整 ASP.NET Core 路線圖: https://aka.ms/aspnet/roadmap
[4].NET 7 SDK: https://dotnet.microsoft.com/download/dotnet/7.0
[5]Visual Studio 2022 預覽版: https://visualstudio.com/preview
[6]Visual Studio 2022 for Mac 預覽版: https://visualstudio.microsoft.com/vs/mac/preview/
[7]重大更改: https://docs.microsoft.com/dotnet/core/compatibility/7.0#aspnet-core
[8]dotnet/aspnetcore#21513: https://github.com/dotnet/aspnetcore/issues/21513
[9]ListenOptions.UseHttps: https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.hosting.listenoptionshttpsextensions.usehttps
[10]Server Name Indication (SNI): https://wikipedia.org/wiki/Server_Name_Indication
[11]HTTP/3: Avoid per-request cancellation token allocations: https://github.com/dotnet/aspnetcore/pull/42685
[12]HTTP/3: Avoid ConnectionAbortedException allocations: https://github.com/dotnet/aspnetcore/pull/42708
[13]HTTP/3: ValueTask pooling: https://github.com/dotnet/aspnetcore/pull/42760
[14]草案規范: https://ietf-wg-webtrans.github.io/draft-ietf-webtrans-http3/draft-ietf-webtrans-http3.html#name-establishing-a-transport-ca
[15]gRPC JSON 轉碼: https://devblogs.microsoft.com/dotnet/announcing-grpc-json-transcoding-for-dotnet/
[16]Microsoft.AspNetCore.Grpc.Swagger: https://www.nuget.org/packages/Microsoft.AspNetCore.Grpc.Swagger
[17]Blazor 社區站會: https://www.youtube.com/watch?v=-ZSscIhQaRk&list=PLdo4fOcmZ0oX-DBuRG4u58ZTAJgBAeQ-t&index=2
[18]https://www.youtube.com/watch?v=-ZSscIhQaRk&feature=emb_imp_woyt: https://www.youtube.com/watch?v=-ZSscIhQaRk&feature=emb_imp_woyt
[19]GitHub: https://github.com/dotnet/aspnetcore/issues/new