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

語言: CN / TW / HK

原文連結: 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", "[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]

  • 影片地址: 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