ASP.NET Core在.NET 7 RC1中的更新

語言: CN / TW / HK

原文鏈接: http://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", "[email protected]");
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", "[email protected]");
NavigationManager.NavigateToLogin(accessTokenResult.InteractiveRequestUrl, accessTokenResult.InteractionOptions);
}

當無法獲取令牌時,您還可以通過 AuthorizationMessageHandler 指定身份驗證請求選項:

try
{
await httpclient.Get("/orders");

}
catch (AccessTokenNotAvailableException ex)
{
ex.Redirect(requestOptions =>
{
requestOptions.AddAdditionalParameter("login_hint", "[email protected]");
});
}

為身份驗證請求指定的任何其他參數都將傳遞到底層身份驗證庫,然後由其處理。

注意:為msal.js指定附加參數尚未完全實現,但預計將在即將發佈的版本中完成。

處理位置變化事件

.NET 7 中的 Blazor 現在支持處理位置更改事件。這允許您在用户執行頁面導航時警吿用户未保存的工作或執行相關操作。

使用 NavigationManager 服務的 RegisterLocationChangingHandler 方法註冊處理程序用於處理位置更改事件。然後,您的處理程序可以在導航時執行異步工作,或者通過調用 LocationChangingContextPreventNavigation 取消導航。 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 prompt
async 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.NumberJSType.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 完整的證書鏈改進

類型 X509Certificate2CollectionHttpsConnectionAdapterOptions 具有新屬性 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]

  • 視頻地址: http://www.youtube.com/watch?v=-ZSscIhQaRk&feature=emb_imp_woyt [18]

給予反饋

我們希望您喜歡 .NET 7 中的 ASP.NET Core 預覽版。通過在 GitHub [19] 上提交問題,讓我們知道您對這些新改進的看法。

感謝您試用 ASP.NET Core!

參考資料

[1]

http://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-rc-1/: http://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-rc-1/

[2]

.NET 7 Release Candidate 1 (RC1) 現已推出: http://devblogs.microsoft.com/dotnet/announcing-dotnet-7-rc-1

[3]

.NET 7 的完整 ASP.NET Core 路線圖: http://aka.ms/aspnet/roadmap

[4]

.NET 7 SDK: http://dotnet.microsoft.com/download/dotnet/7.0

[5]

Visual Studio 2022 預覽版: http://visualstudio.com/preview

[6]

Visual Studio 2022 for Mac 預覽版: http://visualstudio.microsoft.com/vs/mac/preview/

[7]

重大更改: http://docs.microsoft.com/dotnet/core/compatibility/7.0#aspnet-core

[8]

dotnet/aspnetcore#21513: http://github.com/dotnet/aspnetcore/issues/21513

[9]

ListenOptions.UseHttps: http://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.hosting.listenoptionshttpsextensions.usehttps

[10]

Server Name Indication (SNI): http://wikipedia.org/wiki/Server_Name_Indication

[11]

HTTP/3: Avoid per-request cancellation token allocations: http://github.com/dotnet/aspnetcore/pull/42685

[12]

HTTP/3: Avoid ConnectionAbortedException allocations: http://github.com/dotnet/aspnetcore/pull/42708

[13]

HTTP/3: ValueTask pooling: http://github.com/dotnet/aspnetcore/pull/42760

[14]

草案規範: http://ietf-wg-webtrans.github.io/draft-ietf-webtrans-http3/draft-ietf-webtrans-http3.html#name-establishing-a-transport-ca

[15]

gRPC JSON 轉碼: http://devblogs.microsoft.com/dotnet/announcing-grpc-json-transcoding-for-dotnet/

[16]

Microsoft.AspNetCore.Grpc.Swagger: http://www.nuget.org/packages/Microsoft.AspNetCore.Grpc.Swagger

[17]

Blazor 社區站會: http://www.youtube.com/watch?v=-ZSscIhQaRk&list=PLdo4fOcmZ0oX-DBuRG4u58ZTAJgBAeQ-t&index=2

[18]

http://www.youtube.com/watch?v=-ZSscIhQaRk&feature=emb_imp_woyt: http://www.youtube.com/watch?v=-ZSscIhQaRk&feature=emb_imp_woyt

[19]

GitHub: http://github.com/dotnet/aspnetcore/issues/new