.NET 10 中的 Blazor:新增功能及常见问题

目录

[为什么你的 Blazor 代码即将变得更简单](#为什么你的 Blazor 代码即将变得更简单)

样板问题

[.NET 10:"我们真正修复了状态"版本](#.NET 10:“我们真正修复了状态”版本)

持久状态,不会让你哭泣

[电路状态持久性("我的 WebSocket 连接断开"问题)](#电路状态持久性(“我的 WebSocket 连接断开”问题))

[性能:Blazor .NET 10 基准测试](#性能:Blazor .NET 10 基准测试)

[Blazor .NET 10 中的 JavaScript 互操作](#Blazor .NET 10 中的 JavaScript 互操作)

真正的胜利:制造商的支持

WebAssembly热重载

表单验证源生成器

[404 处理方式合情合理](#404 处理方式合情合理)

导航改进

重新连接界面更新

支持密码认证

[QuickGrid 更新](#QuickGrid 更新)

WebAssembly改进

改进的服务验证

默认响应流

性能诊断

迁移清单

避免常见错误

[1. 过度使用[PersistentState]](#1. 过度使用[PersistentState])

[2. 忘记新的验证注册](#2. 忘记新的验证注册)

[3. 假设通行密钥在所有地方都有效](#3. 假设通行密钥在所有地方都有效)

[4. 忽略电路暂停/恢复](#4. 忽略电路暂停/恢复)

何时升级

常见问题解答

[.NET 10 是 LTS 版本吗?](#.NET 10 是 LTS 版本吗?)

[Blazor .NET 10 的最大改进是什么?](#Blazor .NET 10 的最大改进是什么?)

[Blazor .NET 10 是否支持密码?](#Blazor .NET 10 是否支持密码?)

[.NET 10 中的 Blazor JavaScript 包体积缩小了多少?](#.NET 10 中的 Blazor JavaScript 包体积缩小了多少?)

[我可以在 .NET 10 中使用 Blazor WebAssembly 的热重载功能吗?](#我可以在 .NET 10 中使用 Blazor WebAssembly 的热重载功能吗?)

[如何从 .NET 9 迁移到 .NET 10?](#如何从 .NET 9 迁移到 .NET 10?)

最后想说的话


如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

探索 Blazor .NET 10 的所有新特性:持久状态管理、改进的 JavaScript 互操作性、密钥身份验证以及显著的性能提升。这是一份面向 .NET 开发人员的全面指南,其中包含代码示例。

为什么你的 Blazor 代码即将变得更简单

Blazor 在 .NET 10 中的出现,标志着微软 Web UI 框架向前迈出了重要一步。我还记得 Blazor 曾经是 .NET 圈子里一个特立独行的孩子。"你想在浏览器里运行 C#?这太可爱了。" 快进到 2025 年,Blazor .NET 10 不再是弱者,而是真正的竞争者。

Blazor 一直都很好用。但有些图案需要比实际需要的更繁琐的步骤。

.NET 10 最终解决了之前存在的一些问题。有关官方概述,请参阅微软的ASP.NET Core 10.0 新特性文档。

样板问题

很多开发者都经历过这种情况:你启动了一个 Blazor 项目,兴致勃勃,编写组件,组件运行正常,一切顺利。

然后你的老板问:"为什么页面在导航时会闪白光?"

然后你发现了预渲染、水合以及双重渲染问题。框架处理了所有这些,但你必须自己编写底层逻辑。手动序列化状态、权衡OnInitializedAsync各种方案OnAfterRenderAsync、构建那些感觉本应内置的抽象层。

六个月后,你的Program.cs

builder.Services.AddScoped<IStateContainer, StateContainer>();

builder.Services.AddScoped<IPreRenderStateService, PreRenderStateService>();

builder.Services.AddScoped<IHydrationHelper, HydrationHelper>();

builder.Services.AddScoped<IComponentStateManager, ComponentStateManager>();

builder.Services.AddScoped<ICircuitHandler, CustomCircuitHandler>();

builder.Services.AddSingleton<IReconnectionStateTracker, ReconnectionStateTracker>();

// Services that worked great, but shouldn't have been your job to write

获取天气数据的组件?它获取了两次。一次是在预渲染阶段,一次是在交互模式下。你的 API 团队肯定恨死你了。

.NET 10:"我们真正修复了状态"版本

让我来向您展示一下新增功能,以及它为何如此重要。

持久状态,不会让你哭泣

.NET 10 之前:

@inject PersistentComponentState ApplicationState

@code {

private WeatherForecast[]? forecasts;

private PersistingComponentStateSubscription _subscription;

protected override async Task OnInitializedAsync()

{

_subscription = ApplicationState.RegisterOnPersisting(PersistData);

if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>("forecasts", out forecasts))

{

forecasts = await FetchForecasts();

}

}

private Task PersistData()

{

ApplicationState.PersistAsJson("forecasts", forecasts);

return Task.CompletedTask;

}

public void Dispose()

{

_subscription.Dispose();

}

}

仅仅为了避免重复获取数据,就需要 25 行繁琐的代码。每个组件都是如此。

.NET 10 之后:

@code {

PersistentState

public WeatherForecast[]? Forecasts { get; set; }

protected override async Task OnInitializedAsync()

{

Forecasts ??= await FetchForecasts();

}

}

一个属性。就这么简单。运行时会处理序列化、数据填充和清理。你的 API 团队甚至可能再次邀请你共进午餐。在官方文档中了解更多关于Blazor 状态管理的信息。

电路状态持久性("我的 WebSocket 连接断开"问题)

你肯定遇到过这种情况:用户填写了一份复杂的表格,然后网络出现故障,WebSocket 连接断开,Blazor 服务器重新连接。

他们的所有数据?都没了。他们得重新开始。他们会放弃你的应用。他们会写差评。

.NET 10 修复了这个问题:

// When the user goes idle or connection is unstable

Blazor.pause();

// Later, when they're back

await Blazor.resume();

在连接断开之前调用时Blazor.pause(),.NET 10 会将电路状态持久化到浏览器存储中。即使服务器上的原始电路已被清除,您也可以稍后恢复连接。实际上,这种持久性取决于您的服务器设置和浏览器的存储生命周期。请将其理解为"更具弹性",而不是"无限会话永存"。

这使得 Blazor Server 在高要求的企业级应用场景中更具弹性。更多详情,请参阅 Microsoft 的Blazor Server 重新连接文档。

性能:Blazor .NET 10 基准测试

以下是一个典型的 Blazor Web 应用的修改前后对比图(具体数值会根据配置和应用结构而有所不同):

资产 .NET 9 .NET 10 改进
blazor.web.js 约183 KB 约43 KB 缩小约 76%
启动清单 单独的文件 内联dotnet.js 请求减少 1 次
资产交付 嵌入式资源 静态指纹识别 更好的缓存

那个 JavaScript 包?它已经大幅精简了。你的 Lighthouse 分数会感谢你的。

等等,还有更多惊喜。.NET 10 会在 Blazor Web 应用中通过 Link 标头自动预加载 Blazor 框架资源,并在独立 WebAssembly 中启用高优先级下载。运行时会页面渲染时下载资源,而不是渲染后再下载。

首次渲染完成,用户可以看到内容。与此同时,Blazor 运行时在后台下载。无需任何特殊组件------框架会自动处理。

这就像"这个应用运行缓慢"和"这个应用运行瞬间完成"之间的区别。

Blazor .NET 10 中的 JavaScript 互操作

旧版 JS 的互操作性是......函数式的。你可以调用函数,可以传递基本类型,但你只能祈祷 JSON 序列化不会崩溃。

.NET 10 增加了实际的对象语义:

// Create a JS object instance

var chart = await JS.InvokeConstructorAsync<IJSObjectReference>(

"Chart",

canvasElement,

chartConfig

);

// Read properties

var currentValue = await chart.GetValueAsync<int>("currentValue");

// Set properties

await chart.SetValueAsync("animationDuration", 500);

// For performance-critical code (in-process only)

var syncValue = chart.GetValue<int>("dataLength");

现在你操作的是实际对象,不再只是字符串和祈祷文了。对于嵌套很深的属性路径,通常仍然需要编写一个简单的 JavaScript 辅助函数,并从 .NET 中调用它。完整的 API 参考请参见"从 .NET 调用 JavaScript" 。

真正的胜利:制造商的支持

以前,创建JS对象看起来像这样:

await JS.InvokeVoidAsync("eval", "window.myChart = new Chart(canvas, config)");

var reference = await JS.InvokeAsync<IJSObjectReference>("eval", "window.myChart");

评估。在生产代码中。我见过。我也写过。我们都见过。

现在:

var myChart = await JS.InvokeConstructorAsync<IJSObjectReference>("Chart", canvas, config);

无需评估,不会造成全球污染,只有纯净的互操作性。

WebAssembly热重载

Blazor 的热重载功能一直褒贬不一。服务器端表现相当不错。WebAssembly 端呢?需要手动配置,而且有时根本就没法配置。

.NET 10 迁移到了 WebAssembly 的通用热重载实现。SDK 现在会自动处理它。

<!-- This is now true by default for Debug builds -->

<PropertyGroup>

<WasmEnableHotReload>true</WasmEnableHotReload>

</PropertyGroup>

您无需添加此功能,它已启用。编辑.razor文件并保存,即可立即查看更改。无需重新构建,无需刷新浏览器,也无需任何配置。

对于具有自定义构建配置的团队:

<!-- Enable for non-Debug configurations -->

<PropertyGroup Condition="'$(Configuration)' == 'Staging'">

<WasmEnableHotReload>true</WasmEnableHotReload>

</PropertyGroup>

工作流程终于达到了应有的水平:编辑代码、保存、查看更改。Blazor WASM 的内部开发循环现在几乎可以与 JavaScript 框架多年来一直拥有的流程相媲美。

表单验证源生成器

这一点虽然细微,但却很重要。

**.NET 10 之前:**验证使用反射。每次表单提交时,运行时都会遍历模型,查找属性并构建验证器。虽然可行,但对 AOT 不友好,而且速度也不快。

.NET 10 之后:

// Program.cs

builder.Services.AddValidation();

// Your model

ValidatableType\] // New: enables source-generated validators in .NET 10 public class OrderForm { \[Required

public string CustomerName { get; set; }

Range(1, 100)

public int Quantity { get; set; }

ValidateComplexType\] // Now works with the source generator for nested objects public Address ShippingAddress { get; set; } \[ValidateEnumeratedItems\] // Collection items validated via the generator public List\ Items { get; set; } } 源代码生成器在编译时运行,它会创建优化的验证器,无需运行时反射,兼容 AOT,速度更快。有关实现细节,请参阅[Blazor 表单和验证。](https://learn.microsoft.com/en-us/aspnet/core/blazor/forms "Blazor 表单和验证。") 最后------*终于* ------嵌套对象验证功能真正实现了。无需再使用任何自定义`ValidationAttribute`技巧。 ### **404 处理方式合情合理** 我们之前是如何处理 404 错误的? @page "/products/{id}" @if (_notFound) { \ } else if (_loading) { \ } else { \ } @code { private bool _loading = true; private bool _notFound = false; private Product? _product; protected override async Task OnInitializedAsync() { _product = await ProductService.GetById(Id); _notFound = _product == null; _loading = false; } } 每个组件。每个页面。手动跟踪"这个东西是否存在"。 **.NET 10:** @page "/products/{id}" @inject NavigationManager Nav @code { private Product? _product; protected override async Task OnInitializedAsync() { _product = await ProductService.GetById(Id); if (_product is null) { Nav.NotFound(); // That's it. That's the whole thing. return; } } } 支持服务器端渲染 (SSR)。支持交互模式。支持所有平台。框架会处理 404 响应、页面显示等所有操作。 新模板甚至包含一个`NotFound.razor`开箱即用的组件。只需自定义一次,即可在任何地方使用。 ![](https://i-blog.csdnimg.cn/direct/a008124775e74b5ca4a8422fa1cd2fa3.png) ### **导航改进** 这件事困扰了我好几年。 用户正在阅读一个很长的页面。他们点击了一个过滤器,更新了查询字符串。Blazor 跳转到了"新"的 URL。页面滚动到顶部。用户找不到刚才阅读的位置。用户咒骂你的名字。 **已在 .NET 10 中修复。**同页面导航不再滚动到顶部。查询字符串更改会保留视口。片段更改也能正常工作。 所以: \ Electronics \ 启用此功能后`NavLinkMatch.All`,即使您`&sort=price`在 URL 中添加了参数,它仍然有效。查询字符串和片段在匹配时将被忽略。 细节决定成败。 ### **重新连接界面更新** Blazor Server 中的默认重新连接模态框一直看起来......还不错。很普通。就像是 2019 年由一群人共同设计的(因为它确实是)。 .NET 10 模板包含一个新`ReconnectModal`组件: Components/ ├── ReconnectModal.razor ├── ReconnectModal.razor.css # Collocated styles └── ReconnectModal.razor.js # Collocated scripts 它符合CSP标准。它可自定义。它看起来就像是你的应用的一部分。 而且还有一个新活动可以参与: document.addEventListener('components-reconnect-state-changed', (e) =\> { console.log(\`Reconnection state: ${e.detail.state}\`); // States: 'connecting', 'connected', 'failed', 'retrying' (new!) }); 状态`retrying`已更新。现在您可以显示"正在尝试重新连接,这是第 3 次尝试,共 10 次......"而不是一直显示加载中。 ![](https://i-blog.csdnimg.cn/direct/f503634d671341f4abecb6ce700db688.png) ### **支持密码认证** ASP.NET Core Identity 现在支持 WebAuthn/FIDO2。简而言之,就是指纹和人脸登录、硬件安全密钥以及防钓鱼身份验证。 // Program.cs builder.Services.AddIdentityCore\(options =\> { options.SignIn.RequireConfirmedAccount = true; options.Stores.SchemaVersion = IdentitySchemaVersions.Version3; // Enables passkeys }) .AddEntityFrameworkStores\() .AddSignInManager() .AddDefaultTokenProviders(); Blazor Web App 模板搭建了密码端点和 UI------大部分工作是配置,而不是手动编写 WebAuthn: * 注册通行密钥 * 列出已注册的通行密钥 * 移除密码 * 使用密码登录 * 无密码账户创建(是的,完全支持无密码流程) 无需第三方库,无需复杂的 WebAuthn 实现,它就能正常工作。有关实现指南,请参阅[ASP.NET Core 身份验证简介](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity "ASP.NET Core 身份验证简介")。 ### **QuickGrid 更新** 如果您正在使用[QuickGrid](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/quickgrid "QuickGrid")(强烈推荐使用,它非常出色),以下两项改进将提升您的使用体验: \ \ \ \ @code { private string GetRowClass(Order order) =\> order.Status switch { OrderStatus.Overdue =\> "row-danger", OrderStatus.Pending =\> "row-warning", _ =\> "" }; } 基于数据的动态行样式。终于实现了。 列选项如下: private async Task ApplyFilter() { // Apply your filter logic await _grid.HideColumnOptionsAsync(); // Close the popup programmatically } 小事,大效率提升。 ![](https://i-blog.csdnimg.cn/direct/2666accd675d4fdca3b7601ed38e6fe8.png) ### **WebAssembly改进** #### **改进的服务验证** 你知道什么最有趣吗?注册一个服务时设置了错误的生命周期。然后在运行时发现它。在生产环境中。 // Misconfigured lifetimes are now caught with clear diagnostics builder.Services.AddScoped\(); // Oops, should be Singleton builder.Services.AddSingleton\(); // Depends on scoped service 在 .NET 10 WebAssembly 中,配置错误的生命周期(例如依赖于作用域服务的单例)会被清晰地诊断出来,而不会在运行时崩溃。这是由构建管道捕获的,而不是用户捕获的。 #### **默认响应流** var response = await Http.GetAsync("/api/large-dataset"); var stream = await response.Content.ReadAsStreamAsync(); // In .NET 10, this uses BrowserHttpReadStream automatically // Memory efficient. No massive allocations. 大文件下载不再占用所有内存。浏览器的流媒体功能得到了充分利用。 #### **性能诊断** WASM 的新型诊断工具: * CPU性能概况 * 内存转储 * 性能计数器 * 原生 WebAssembly 指标 最后,您可以找出应用运行缓慢的*原因* ,而不仅仅是知道它运行缓慢。有关 Blazor WebAssembly 的更多信息,请参阅[ASP.NET Core Blazor WebAssembly](https://learn.microsoft.com/en-us/aspnet/core/blazor/hosting-models#blazor-webassembly "ASP.NET Core Blazor WebAssembly")。 ![](https://i-blog.csdnimg.cn/direct/f8d81aacf2bd4a599aeceeb298b5de4c.png) ### **迁移清单** 要从 .NET 9 升级?请检查以下事项: * \[ \] 更新 TFM 至`net10.0` * \[ \]`builder.Services.AddValidation()`如果使用新的验证方式,请添加 * \[ \] 查看重新连接界面------新组件已可用,但未自动应用 * \[ \] 测试导航行为------同页面导航不再滚动 * \[ \] 考虑`[PersistentState]`替换手动状态持久化 * \[ \] 查看 JS 互操作性------新增 API,实现更简洁的对象处理 * \[ \] 如果使用身份认证,请测试密码密钥支持 ### **避免常见错误** #### **1. 过度使用`[PersistentState]`** // Don't do this \[PersistentState

public DateTime LastClick { get; set; } // Why are you persisting this?

PersistentState

public bool IsMenuOpen { get; set; } // UI state doesn't need persistence

持久化数据,而非用户界面状态。序列化开销并非没有。

2. 忘记新的验证注册

// This won't work with [ValidatableType]

builder.Services.AddRazorComponents();

// You need this too

builder.Services.AddValidation();

源生成器创建验证器AddValidation()并注册它们。

3. 假设通行密钥在所有地方都有效

// Check for support first

if (await PasskeyService.IsSupported())

{

// Show passkey options

}

else

{

// Fallback to password

}

老款 iOS 系统上的 Safari 浏览器?某些安卓浏览器?策略奇葩的企业网络?密码支持情况不一。务必准备备用方案。

4. 忽略电路暂停/恢复

// The connection died, but you didn't pause first

// State is lost. User is sad.

// Do this instead

window.addEventListener('beforeunload', () => {

Blazor.pause();

});

只有当你明确告诉 Blazor 持久化电路状态时,电路状态持久化才会生效。

何时升级

情况 推荐
新项目 当然要从.NET 10开始。
.NET 9,太棒了! 如果您对升级比较谨慎,可以考虑等待第一个 .NET 10 服务更新。
.NET 9 遇到状态问题 现在就升级吧,[PersistentState]光这一点就值回票价。
.NET 8 LTS 你可以在2026年11月之前完成迁移。但第10年也是长期支持计划(LTS)。做好迁移计划吧。
.NET 6 或更早版本 你在干什么?昨天就升级了。

.NET 10 是一个长期支持 (LTS) 版本,提供三年支持。它是生产应用程序的理想选择。

常见问题解答

.NET 10 是 LTS 版本吗?

是的,.NET 10 是一个长期支持 (LTS) 版本,微软提供三年的支持。这使其成为需要稳定性和长期维护的生产应用程序的理想选择。之前的 LTS 版本是 .NET 6 和 .NET 8。

Blazor .NET 10 的最大改进是什么?

可以说,这个[PersistentState]属性的加入是影响最大的改动。它将 25 行以上的手动状态序列化代码简化为一个属性,从而消除了预渲染和水合期间的重复渲染问题和冗余 API 调用。

Blazor .NET 10 是否支持密码?

是的,ASP.NET Core Identity 现在内置了对 WebAuthn/FIDO2 密钥身份验证的支持。这使得指纹登录、面容 ID 和硬件安全密钥无需第三方库即可使用。Blazor Web 应用模板会自动生成必要的端点和 UI 组件。

.NET 10 中的 Blazor JavaScript 包体积缩小了多少?

.NET 10 中,该blazor.web.js软件包的大小从 .NET 9 的约 183 KB 减少到约 43 KB,体积缩小了约 76%。此外,启动清单现在已内联,从而在启动过程中减少了一次额外的 HTTP 请求。

我可以在 .NET 10 中使用 Blazor WebAssembly 的热重载功能吗?

是的,Blazor WebAssembly Debug 版本现在默认启用热重载。编辑文件.razor并保存后,无需重新构建或刷新浏览器即可立即看到更改。对于非 Debug 配置(例如 Staging),您可以使用以下命令手动启用它<WasmEnableHotReload>true</WasmEnableHotReload>

如何从 .NET 9 迁移到 .NET 10?

更新目标框架名称 (TFM) net10.0builder.Services.AddValidation()如果使用新的源生成验证器,请添加相关配置,查看新的重新连接 UI 组件,并测试导航行为的更改。考虑使用[PersistentState]属性替换手动状态持久化。有关详细信息,请参阅迁移清单部分。

最后想说的话

每次 Blazor 版本发布,我都会寻找能够让开发体验更流畅、减少缺陷的改进之处。

.NET 10 表现出色。

Blazor 已经成熟,可以投入生产环境多年------许多企业自 2019 年以来就一直在成功运行它。但 .NET 10 更进一步。状态管理不再仅仅是函数式的,而是更加优雅。性能卓越。JavaScript 互操作性也更加现代化。开发者体验显著提升。

它完美吗?不。调试机制仍需改进。组件库生态系统仍然比 React 小。WASM 中的一些极端情况仍然需要变通方法。

但 .NET 10 消除了我过去在推荐 Blazor 时提到的许多注意事项。它不仅是 .NET 团队的可靠选择,而且完全可以与任何现代 Web 框架相媲美。

.NET 10 提高了标准。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

相关推荐
csdn_aspnet4 小时前
Asp.Net Core 10.0 中的 Blazor 增强功能
前端·后端·asp.net·blazor·.net10
zhojiew24 天前
使用envoy配置jwt校验和ratelimit限流以及通过wasm扩展统计llm消耗token
wasm·envoy
狗都不学爬虫_1 个月前
JS逆向 -最新版 盼之(decode__1174、ssxmod_itna、ssxmod_itna2)纯算
javascript·爬虫·python·网络爬虫·wasm
老百姓懂点AI1 个月前
[WASM实战] 插件系统的安全性:智能体来了(西南总部)AI调度官的WebAssembly沙箱与AI agent指挥官的动态加载
人工智能·wasm
坚定信念,勇往无前1 个月前
unity发布BuildWebGL.wasm 加载过慢
unity·wasm
csdn_aspnet1 个月前
.NET 10 中的 ASP.NET Core Identity — 从“登录页面”到生产级安全
asp.net·.net core·identity·.net10
狗都不学爬虫_2 个月前
JS逆向 - 最新版某某安全中心滑块验证(wasm设备指纹)
javascript·爬虫·python·网络爬虫·wasm
REDcker2 个月前
WASM 软解 H.265 性能优化详解
性能优化·wasm·h.265