asp.net core在.net 7 rc1中的更新

asp.net core在.net 7 rc1中的更新

net 7 release candidate 1 (rc1) 現已推出,其中包括對 asp.net core 的許多重大新改進。

最后更新 2022/9/15 上午9:23
Daniel Roth
预计阅读 17 分钟
分类
.NET
标签
.NET C# ASP.NET Core

原文链接:https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-rc-1/

原文作者:daniel roth

翻譯:沙漠盡頭的狼(谷歌翻譯加持)

.NET 7 Release Candidate 1 (RC1) 现已推出,其中包括对 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 路线图

開始使用

要开始使用 .NET 7 Release Candidate 1 中的 ASP.NET Core,请安装 .NET 7 SDK

如果你在 Windows 上使用 Visual Studio,我们建议安装最新的Visual Studio 2022 预览版。如果您使用的是 macOS,我们建议您安装最新的Visual Studio 2022 for Mac 预览版

要安裝最新的 .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 中的重大更改的完整列表。

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方法注册处理程序用于处理位置更改事件。然后,您的处理程序可以在导航时执行异步工作,或者通过调用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

更快的 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使用 HTTP/3。Kestrel 提供了用于配置连接证书的高级选项,例如拦截到Server Name Indication (SNI)

以下示例顯示如何使用 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 對 webtransport 的實驗性 kestrel 支持

我们很高兴地宣布在 Kestrel 中对基于 HTTP/3 的 WebTransport 的内置实验性支持。此功能是由我们优秀的实习生 Daniel 编写的!WebTransport 对于类似于 WebSockets 的传输协议是一个新的草案规范,它允许每个连接使用多个流。这对于拆分通信通道并因此避免线头阻塞很有用。例如,考虑一个基于网络的在线游戏,其中游戏状态在一个双向流上传输,玩家对游戏语音聊天功能的语音在另一个双向流上传输,而玩家的控制在单向流上传输。使用 WebSockets,这一切都需要放在单独的连接上或压缩到单个流中。使用 WebTransport,您可以将所有流量保留在一个连接上,但将它们分成自己的流,如果一个流阻塞,其他流将继续不间断。

其他詳細信息將在單獨的博客文章中提供。

對 grpc json 轉碼的實驗性 openapi 支持

gRPC JSON 转码是 .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的包引用。版本必须为 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 社区站会

給予反饋

我们希望您喜欢 .NET 7 中的 ASP.NET Core 预览版。通过在GitHub 上提交问题,让我们知道您对这些新改进的看法。

感謝您試用 asp.net core!

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 2024/6/20

codewf.eventbus:輕量級事件總線,讓通信更流暢

codewf.eventbus,一款靈活的事件總線庫,實現模塊間解耦通信。支持多種.net項目類型,如wpf、winforms、asp.net core等。採用簡潔設計,輕鬆實現命令的發布與訂閱、請求與響應。通過有序的事件處理,確保事件得到妥善處理。簡化您的代碼,提升系統可維護性。

继续阅读
同分类 / 同标签 2024/1/19

基於 .net 的 fluentvalidation 驗證教程

fluentvalidation 是一個基於 .net 開發的驗證框架,開源免費,而且優雅,支持鏈式操作,易於理解,功能完善,還是可與 mvc5、webapi2 和 asp.net core 深度集成,組件內提供十幾種常用驗證器,可擴展性好,支持自定義驗證器,支持本地化多語言。

继续阅读