.NET 7预览版现已发布,其中包括对ASP.NET Core的许多伟大的新改进。
下面是这个预览版中的新内容摘要:
- 新的Blazor WebAssembly加载页面
- Blazor数据绑定的get/set/after修改器
- Blazor虚拟化改进
- 使用传递状态
NavigationManager - 对WebAssembly的额外
System.Security.Cryptography支持 - 更新Angular和React模板
- gRPC JSON转码的性能
- 认证将使用单一方案作为
DefaultScheme IFormFile/IFormFileCollection在最小的API中对认证请求的支持- 新的问题细节服务
- 诊断中间件更新
- 新的
HttpResults接口
关于为.NET 7计划的ASP.NET Core工作的更多细节,请参阅GitHub上完整的.NET 7的ASP.NET Core路线图。
开始使用
要开始使用.NET 7 Preview 7中的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
注意:用.NET 7 SDK和.NET 7 WebAssembly构建工具构建.NET 6 Blazor项目,目前还不支持。这将在未来的.NET 7更新中解决:dotnet/runtime#65211。
升级一个现有的项目
要将现有的ASP.NET Core应用程序从.NET 7 Preview 6升级到.NET 7 Preview 7:
- 将所有Microsoft.AspNetCore.*包的引用更新为
7.0.0-preview.7.*。 - 将所有Microsoft.Extensions.*包的引用更新到
7.0.0-preview.7.*。
另请参见ASP.NET Core for .NET 7中的全部中断变化列表。
新的Blazor加载页面
Blazor WebAssembly项目模板有一个新的加载UI,显示应用程序的加载进度。

新的加载界面是在Blazor WebAssembly模板中用HTML和CSS实现的,使用Blazor WebAssembly提供的两个新的CSS自定义属性(变量)。
--blazor-load-percentage:已加载的应用程序文件的百分比。--blazor-load-percentage-text:已加载的应用程序文件的百分比,四舍五入到最近的整数。
使用这些新的CSS变量,你可以创建一个自定义的加载UI,与你自己的Blazor WebAssembly应用程序的风格相匹配。
Blazor数据绑定get/set/after修改器
Blazor提供了一个强大的数据绑定功能,用于在UI元素或组件参数与.NET对象之间建立双向绑定关系。在.NET 7中,您现在可以使用新的@bind:after 修改器在绑定事件完成后轻松运行异步逻辑:
<input @bind="searchText" @bind:after="PerformSearch" />
@code {
string searchText;
async Task PerformSearch()
{
// ... do something asynchronously with 'searchText' ...
}
}
在这个例子中,PerformSearch async方法将在检测到搜索文本的任何变化后自动运行。
现在为组件参数设置绑定也更容易了。组件可以通过为值和回调定义一对参数来支持双向数据绑定,当值发生变化时回调会被调用。新的@bind:get 和@bind:set 修改器现在使创建一个与底层UI元素绑定的组件参数变得简单:
<input @bind:get="Value" @bind:set="ValueChanged" />
@code {
[Parameter] public TValue Value { get; set; }
[Parameter] public EventCallback<TValue> ValueChanged { get; set; }
}
@bind:get 和@bind:set 修改器总是一起使用。@bind:get 修饰符指定了要绑定的值,而@bind:set 修饰符则指定了一个回调,当该值发生变化时就会调用。
Blazor虚拟化的改进
Blazor的Virtualize 组件渲染了一个间隔元素来定义滚动区域的垂直高度。默认情况下,它使用这样的一个div 元素:
<div style="height: 12345px"></div>
然而,在某些情况下,父元素可能不允许子div 元素。例如,父元素可能是一个tbody ,它只允许子元素tr 。对于这些情况,你现在可以使用新的SpacerElement 参数来配置Virtualize 使用的间隔元素:
<tbody>
<Virtualize SpacerElement="tr">...</Virtualize>
</tbody>
传递状态使用NavigationManager
现在你可以在Blazor应用程序中使用NavigationManager ,在导航时传递状态。
navigationManager.NavigateTo("/orders", new NavigationOptions { HistoryEntryState = "My state" });
这种机制允许不同页面之间进行简单的通信。指定的状态会被推送到浏览器的历史堆栈中,以便以后在监听位置改变事件时,可以使用NavigationManager.HistoryEntryState 属性或LocationChangedEventArgs.HistoryEntryState 属性来访问它。
在WebAssembly上的额外System.Security.Cryptography 支持
在WebAssembly上运行时,.NET 6支持SHA系列的散列算法。.NET 7通过在可能的情况下利用SubtleCrypto,并在无法使用SubtleCrypto时退回到.NET的实现,实现更多的加密算法。在.NET 7预览版中,以下算法现在在WebAssembly上得到支持:
- sha1, sha256, sha384, sha512
- hmacsha1, hmacsha256, hmacsha384, hmacsha512
- Aes (只支持CBC模式)
- Rfc2898DeriveBytes (PBKDF2)
- 香港DF
更新了Angular和React模板
我们将Angular项目模板更新为Angular 14,React项目模板更新为React 18.2。
gRPC JSON转码的性能
gRPC JSON转码是.NET 7中的一项新功能,用于将gRPC APIs变成RESTful APIs。
.NET 7预览版改善了序列化消息时的性能和内存使用。gRPC JSON转码将gRPC消息序列化为标准化的JSON格式。在Preview 7之前,转码需要一个自定义的JsonConverter ,以定制JSON序列化。这个版本用System.Text.Json的新合约定制功能取代了JsonConverter 。
下面的基准结果比较了使用合同定制之前和之后的gRPC消息序列化。
| 方法 | 平均值 | 比率 | 所分配的 |
|---|---|---|---|
| 序列化消息_转换器 | 386.7 ns | 1.00 | 160 B |
| 序列化信息_合同 | 213.3 ns | 0.55 | 80 B |
| 反序列化消息_转换器 | 296.0 ns | 1.00 | 304 B |
| 反序列化消息_合同 | 167.6 ns | 0.57 | 224 B |
一个自定义的契约和System.Text.Json的高性能序列化器极大地提高了性能和分配。
认证将使用单一方案作为DefaultScheme
作为简化认证工作的一部分,当只注册了一个单一的认证方案时,它将自动作为DefaultScheme ,在这种情况下,就不需要在AddAuthentication() 中指定DefaultScheme 。这种行为可以通过以下方式禁用AppContext.SetSwitch("Microsoft.AspNetCore.Authentication.SuppressAutoDefaultScheme")
IFormFile/IFormFileCollection 支持最小API中的认证请求
在.NET 7预览版1中,我们引入了对使用IFormFile 和IFormFileCollection在最小的API中处理文件上传的支持。.NET预览版7增加了对使用Authorization 头、客户端证书或cookie头的最小API的认证文件上传请求的支持。
在最小的API中没有对防伪的内置支持。然而,它可以使用IAntiforgery 服务来实现。
新的问题细节服务
.NET 7 Preview 7引入了一个基于IProblemDetailsService 接口的新的问题详情服务,用于在你的应用程序中生成一致的问题详情响应。
要添加问题细节服务,请使用IServiceCollection 上的AddProblemDetails 扩展方法:
builder.Services.AddProblemDetails();
然后,你可以通过调用IProblemDetailsService.WriteAsync ,从你的应用程序中的任何一层写出问题细节响应。例如,这里是你如何从中间件生成一个问题细节响应。
httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
if (context.RequestServices.GetService<IProblemDetailsService>() is { } problemDetailsService)
{
return problemDetailsService.WriteAsync(new { HttpContext = httpContext });
}
return ValueTask.CompletedTask;
你可以使用ProblemDetailsOptions ,定制由服务生成的问题细节响应(包括为API控制器自动生成的响应):
builder.Services.AddProblemDetails(options =>
{
options.CustomizeProblemDetails = (context) =>
{
context.ProblemDetails.Extensions.Add("my-extension", new { Property = "value" });
};
});
此外,你可以创建你自己的IProblemDetailsWriter 实现来进行高级定制:
public class CustomWriter : IProblemDetailsWriter
{
// Indicates that only responses with StatusCode == 400
// will be handled by this writer. All others will be
// handled by different registered writers if available.
public bool CanWrite(ProblemDetailsContext context)
=> context.HttpContext.Response.StatusCode == 400;
public Task WriteAsync(ProblemDetailsContext context)
{
//Additional customizations
// Write to the response
context.HttpResponse.Response.WriteAsJsonAsync(context.ProblemDetails);
}
}
在调用AddProblemDetails 方法之前,注册任何IProblemDetailsWriter 实现:
builder.Services.AddSingleton<IProblemDetailsWriter, CustomWriter>();
builder.Services.AddProblemDetails();
诊断中间件的更新
当新的问题细节服务(IProblemDetailsService)被注册时,以下中间件被更新以生成问题细节的HTTP响应:
ExceptionHandlerMiddleware:当没有定义自定义处理程序时,生成问题细节响应,除非不被客户端接受。StatusCodePagesMiddleware:默认生成问题详情响应,除非不被客户端接受。DeveloperExceptionPageMiddleware:当text/html,除非不被客户端接受,否则生成一个问题细节响应。
下面的例子配置了应用程序,以便为所有尚未有正文内容的HTTP客户端和服务器错误响应生成一个问题细节响应:
var builder = WebApplication.CreateBuilder(args);
// Add services to the containers
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.UseStatusCodePages();
//Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapControllers();
app.Run();
新的HttpResults 接口
在.NET 7预览版3中,ASP.NET Core中实现IResult 的类型被公开了。 现在,在这个预览中,我们在Microsoft.AspNetCore.Http.Http 名称空间中引入了新的接口来描述IResult 类型:
Microsoft.AspNetCore.Http.IContentTypeHttpResultMicrosoft.AspNetCore.Http.IFileHttpResultMicrosoft.AspNetCore.Http.INestedHttpResultMicrosoft.AspNetCore.Http.IStatusCodeHttpResultMicrosoft.AspNetCore.Http.IValueHttpResultMicrosoft.AspNetCore.Http.IValueHttpResult<TValue>
有了这些接口,你现在有了一种更通用的方法,可以在运行时检测IResult 类型,这是过滤器实现中的一种常见模式:
app.MapGet("/weatherforecast", (int days) =>
{
if (days <= 0)
{
return Results.BadRequest();
}
var forecast = Enumerable.Range(1, days.Value).Select(index =>
new WeatherForecast (DateTime.Now.AddDays(index), Random.Shared.Next(-20, 55), "Cool"))
.ToArray();
return Results.Ok(forecast);
}).
AddEndpointFilter(async (context,next) =>
{
var result = await next(context);
return result switch
{
IValueHttpResult<WeatherForecast[]> weatherForecastResult => new WeatherHttpResult(weatherForecastResult.Value),
_ => result
};
});
internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
给予反馈
我们希望你喜欢这个.NET 7中的ASP.NET Core预览版。通过在GitHub上提交问题,让我们知道你对这些新的改进有什么看法。
感谢你尝试使用ASP.NET Core!