大家好,我是码农刚子。这是「Radzen 实战」第 1 篇,复盘 SPcbERP 里那些差点出事的真实坑。
SPcbERP 是 PCB 行业 ERP,前端用 Radzen.Blazor 搭。项目跑了小半年,一直稳。
上个月做依赖升级,把 Radzen.Blazor 从 5.x 升到 6.0.0。编译一次过,dotnet run 正常,浏览器一打开——白屏。
控制台报一串看不懂的错。来回折腾两天才理清,一共四个坑,一个比一个隐蔽。
今天全写出来,你升级的时候照着对一遍,能省两天。
01 坑一:NU1107,依赖版本打架
这个坑最直接,编译就报,不会等到运行。
报错原文:
NU1107: Version conflict detected for Microsoft.AspNetCore.Components.Web.
Reference the package directly from the project to resolve this issue.
SPcbERP -> Radzen.Blazor 6.0.0 -> Components.Web (>= 8.0.10)
SPcbERP -> Components.Web (>= 7.0.0)
翻译一下:Radzen.Blazor 6.0.0 要 Components.Web 8.0.10 以上,你项目里直接引了 7.0.0,两边对不上。
麻烦的是,.NET 8 项目里 Components.Web 本来是框架隐式提供的,正常根本不用手写版本。但一旦你因为某个功能手动引了一次,版本就被钉死了,升级 Radzen 时就会撞。
SPcbERP
/ \
Radzen.Blazor 6.0.0 Components.Web
(传递依赖) (项目里手动引用)
| |
要求 >= 8.0.10 要求 >= 7.0.0
\ /
⚡ NU1107 版本冲突
三个办法,按省事程度排:
一、删掉手动引用。 如果那个直接引用不是必需的,删掉,让 Radzen 的传递依赖决定版本。最干净。
二、显式对齐版本。 在 csproj 里把 Components.Web 显式指到 8.0.10 以上,和 Radzen 的要求一致。
三、锁 Radzen 版本。 暂时升不上去就先别升,等依赖链理顺再说。
顺序提醒:先解决 NU1107,再谈其他坑。编译不过,后面的错根本看不到。
02 坑二:DataGrid 分页,Count 得自己赋值
编译过了,页面能开了,但表格分页不对。
RadzenDataGrid 做服务端分页,用 LoadData 事件。6.0 里这个事件的参数类型是 DataGridLoadDataEventArgs,里面有 Skip 和 Top,但没有 Count。
总条数得你自己查出来,赋给 args.Count。不赋值,分页器不知道一共多少条,只能显示一页。
只查数据,忘了 Count:
async Task LoadData(DataGridLoadDataEventArgs args)
{
args.Data = await db.Orders
.OrderBy(o => o.Id)
.Skip(args.Skip).Take(args.Top)
.ToListAsync();
// args.Count 没赋值 → 分页器算不出总页数
}
数据 + 总数一起给:
async Task LoadData(DataGridLoadDataEventArgs args)
{
var query = db.Orders.AsQueryable();
// 总数单独查一次
args.Count = await query.CountAsync();
args.Data = await query
.OrderBy(o => o.Id)
.Skip(args.Skip).Take(args.Top)
.ToListAsync();
}
代价是多一次 COUNT 查询。但这是服务端分页绕不开的成本——分页器要知道总页数,就得知道总数。除非你关掉分页器,改用「上一页/下一页」的游标式导航。
顺带一提:
LoadData在筛选、排序变化时也会触发。你的 Count 查询必须和 Data 查询用同一套筛选条件,否则筛选后页数还是按全表算的,会出现「筛出来 3 条,却有 5 页」。
03 坑三:DialogService 的泛型和默认尺寸
第三个坑是弹窗。表现有两种:要么弹不出来,要么弹出来窄得像手机屏。
6.0 里 DialogService.OpenAsync 的泛型推断更严格了,DialogOptions 的 Width / Height 不显式指定的话,默认值和 5.x 不一样。
靠默认值撑满:
await DialogService.OpenAsync<EditOrder>(
"编辑订单",
new Dictionary<string, object> { { "Id", id } });
// 6.0 里默认宽度变了,弹窗变得很窄
尺寸和泛型都写死:
await DialogService.OpenAsync<EditOrder>(
"编辑订单",
new Dictionary<string, object> { { "Id", id } },
new DialogOptions
{
Width = "800px",
Height = "600px",
Resizable = true
});
还有一个相关的:Close() 的传参。如果你的弹窗要返回值,OpenAsync<T> 的 T 是返回类型,Close(null) 在 6.0 里会因为推断不出类型而编译失败。老老实实写 Close(default(T)) 或者干脆改成 Close(false) 这种能推断出类型的值。
经验:凡是「靠默认值生效」的地方,升级时都要重新显式声明一遍。默认值是库的内部决定,它改了不会通知你。
04 坑四:样式类名变了,自定义 CSS 全失效
这个坑最难查,因为它不报错。
页面看着「没坏」,但变丑了——表格边框没了、按钮圆角没了、对话框标题栏变白。
原因是 6.0 调整了组件生成的 DOM 结构和 CSS 类名。你项目里针对老类名写的覆盖样式,一条都不生效了。
我的建议是:别去覆盖 Radzen 的具体类名,用它的主题 CSS 变量。 类名是内部实现,换个版本就可能变;CSS 变量才是对外承诺的接口。
排查方法也很土但有效:升级后拿浏览器 DevTools 对着一个表格、一个按钮、一个弹窗,逐个对比 DOM 和计算样式。半小时能捞干净。
05 升级 Radzen 的避坑清单
| 时机 | 动作 |
|---|---|
| 升级前 | 翻一遍 release notes 里的 breaking changes,别只看版本号 |
| 升级前 | 先看依赖树,把 NU1107 这类冲突提前排掉 |
| 升级后 | 服务端分页的表格,逐个确认 Count 有回填 |
| 升级后 | 弹窗全部显式指定 Width/Height 和泛型参数 |
| 升级后 | 过一遍视觉回归,重点看表格、按钮、对话框 |
| 长期 | 锁死包版本,别用浮动版本号,升级当成一次小项目做 |
四个坑里,NU1107 是硬错误,编译就拦你;剩下三个都是软错误——不报错,只是行为变了。软错误才最耗时间,因为你得先意识到「它变了」。
一句话总结:升级组件库,别只看版本号。依赖冲突先排掉,靠默认值的地方全部显式写一遍,升完做一次视觉回归。
你在 Radzen 或者别的组件库上栽过最贵的坑是啥?评论区唠唠。
转发给正在做依赖升级的同事,少走我们趟过的弯路。
关注 CSharp精选营,每周二四 get 能直接抄的 C# 实战。
下一篇聊:SaveChanges 一万行?换批量操作快 10 倍。
关于作者
码农刚子,六年 ERP / 制造业系统开发,专注 C# / .NET / Blazor。
博客:https://www.coderlog.net/ 公众号:CSharp精选营
暂无评论,来抢沙发吧~