今天聊一个选型话题。新项目到底选 Blazor 还是 Razor Pages?我两种都试过,交过学费,今天说点不绕弯的结论。
先说结论
别二选一。混合用。 核心管理后台用 Blazor Server,对外简单页面用 Razor Pages。这不是骑墙,是秦巴牧云项目用血泪换出来的经验。
下面讲讲为什么,以及我交了多少学费。
当初为什么全选了 Blazor
2024 年初启动秦巴牧云项目。一个养殖场管理系统,管理端有库存管理、饲料配方、批次追溯、报表统计,对外有供应商对账页面和饲养员小程序的 WebView 页。
当时我被 Blazor Server 的卖点打动了:
不用写 JavaScript。C# 全栈,前后端一个项目,组件复用,SignalR 实时通信。场长要看实时库存?一个 @onclick 搞定,不用手写 AJAX。
听起来太香了。我把整个项目都建在了 Blazor Server 上。管理端、供应商页面、饲养员 WebView,全是 .razor 文件。
三个月后我开始后悔。
学费一:供应商页面根本不需要 Blazor
供应商对账页面长什么样?一个表单:选供应商、选月份、点查询、看表格。没有实时更新,没有复杂交互,没有拖拽。
用 Razor Pages 写,就是一个 GET 请求渲染页面,一个 POST 请求提交查询,返回带数据的页面。完事。
用 Blazor Server 写呢?页面打开时建立 SignalR 长连接,服务端维护一个组件树,用户点「查询」时通过 WebSocket 发一个事件到服务端,服务端重新渲染组件,把 diff 通过 WebSocket 推回客户端。
为了一个查询按钮,我在服务端维护了一个 WebSocket 连接。供应商有 30 多家,同时在线看对账的可能就三五个人,但这三五个人各占一个连接,各占服务端内存。
这就是杀鸡用牛刀。Blazor 的交互能力对这种页面是浪费,但它的连接开销是实打实的成本。
学费二:饲养员 WebView 里 Blazor Server 翻车
饲养员在小程序 WebView 里打开 Blazor 页面。养殖场在山里,4G 信号不稳定。
Blazor Server 的致命弱点:每次交互都要走网络。 点一个按钮、切一个 tab、展开一个折叠面板,都得通过 SignalR 发到服务端再推回来。信号差的时候,点一下等三秒才响应。饲养员的反馈是「这破系统卡死了」。
Razor Pages 不一样。页面是服务端渲染好整个 HTML 一次性发过来的。打开页面就完了,后续点链接是另一个 HTTP 请求,浏览器原生的加载体验,不会卡在「等 WebSocket 回包」上。
更关键的是,SignalR 连接在弱网下断了还得重连。重连期间整个页面不响应。饲养员不知道页面断了,点哪都没反应,以为系统坏了。
最后饲养员 WebView 那几个页面,我全用 Razor Pages 重写了。一个 .cshtml + 一个 .cshtml.cs,简单粗暴,稳定如老狗。
学费三:简单 CRUD 页面 Blazor 更啰嗦
一个标准的列表+新增+编辑+删除页面,Razor Pages 的写法:
Razor Pages 写法:
// Pages/FeedList.cshtml.cs
public class FeedListModel : PageModel
{
private readonly AppDb db;
public List<FeedStock> Items { get; set; }
public FeedListModel(AppDb db) => this.db = db;
public async Task OnGetAsync() =>
Items = await db.FeedStocks.ToListAsync();
}
<!-- Pages/FeedList.cshtml -->
@page
@model FeedListModel
<table>
@foreach (var f in Model.Items) { <tr>...</tr> }
</table>
一个文件搞完。逻辑在 PageModel,视图在 cshtml,HTTP 语义在 @page 指令里自动处理。
同样的页面用 Blazor 写,你得处理:组件生命周期 OnInitializedAsync、状态管理(数据列表放哪、刷新怎么触发)、导航(NavigationManager)、表单验证(EditForm + DataAnnotationsValidator)。
不是说 Blazor 做不了,而是对简单页面来说,这些是多余的心智负担。 Razor Pages 的 PageModel 天然对应一个 HTTP 请求的生命周期,语义清晰。Blazor 的组件生命周期是为复杂交互设计的,对简单 CRUD 用不上。
秦巴牧云有十几个「列表+表单」页面,全用 Blazor 写的话,每个都得多写三分之一的胶水代码。不划算。
Blazor 的主场在哪里
说完了学费,说说 Blazor 真正不可替代的场景。这些是 Razor Pages 做不到或者做起来很丑的:
场景一:实时看板。 场长要看实时库存、当日领料统计、各圈舍存栏量。数据每隔几秒更新。Blazor Server 用 Timer + StateHasChanged + IAsyncEnumerable,服务端推着 UI 更新。Razor Pages 做这个得手写 JavaScript + SignalR + DOM 操作,回到了前端三件套时代。
场景二:复杂交互表单。 饲料配方页面:选一个原料,自动填充营养成分;改一个配比,实时重算总价和蛋白含量;拖拽排序原料顺序。这种富交互用 Blazor 的组件状态 + 事件绑定写起来顺手,C# 一把梭。Razor Pages 做这个得写大量 JavaScript。
场景三:多步骤向导。 批次追溯录入:五步表单,每步有依赖关系(选了品种才能选圈舍,选了圈舍才能选饲料配方)。Blazor 的组件树天然适合这种有状态的向导。Razor Pages 做多步向导要么用 session 存中间状态,要么每步提交到服务端再渲染回来,体验割裂。
这三个场景是 Blazor 的主场。在这些地方,Blazor 省下的 JavaScript 代码量是实打实的。
秦巴牧云最终的混合架构
┌─────────────────────────────────┐
│ 共享层 │
│ Domain · EF Core · Service · Auth│
└────────┬──────────────┬─────────┘
│引用 │引用
┌────────────┴──┐ ┌───────┴──────────┐
场长/会计 ─内网──→ │ Blazor Server │ │ Razor Pages │ ←外网/弱网─ 供应商
│ (管理后台) │ │ (简单页面) │ ←外网/弱网─ 饲养员
│ │ │ │
│ 实时看板 │ │ 供应商对账 │
│ 配方向导 │ │ 饲养员 WebView │
│ 批次追溯 │ │ 列表+表单 │
│ │ │ │
│ SignalR长连接 │ │ HTTP请求-响应 │
│ 组件状态 │ │ 服务端渲染 │
└────────────────┘ └──────────────────┘
同一个 ASP.NET Core 项目
/admin 路由走 Blazor,/portal 路由走 Razor Pages
共享 Domain + EF Core + Service 层,不重复写业务逻辑
Program.cs 里同时注册:MapBlazor + MapRazorPages
这不是两个项目,是同一个 ASP.NET Core 项目。在 Program.cs 里同时注册两套端点:
var builder = WebApplication.CreateBuilder(args);
// Blazor Server 注册
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
var app = builder.Build();
// Razor Pages 路由(供应商、饲养员页面)
app.MapRazorPages();
// Blazor Server 路由(管理后台)
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
/FeedList 走 Razor Pages,/admin/dashboard 走 Blazor。共享同一套 Domain、EF Core、Service 层,不重复写业务逻辑。
这是 .NET 全栈的优势——一个项目里两种 UI 模式共存,想用哪个用哪个,不用切框架。
怎么选:四条判断线
| 判断维度 | 选 Razor Pages | 选 Blazor Server |
|---|---|---|
| 交互复杂度 | 列表+表单,点链接跳页 | 拖拽、实时更新、多步向导 |
| 网络环境 | 弱网、移动端 WebView | 内网、稳定宽带 |
| 并发用户数 | 不确定/波动大 | 可控(几十到几百) |
| JavaScript 量 | 几乎没有就用 JS | 否则得写一堆 JS |
四条里命中两条以上,方向就明确了。不确定的页面,先按 Razor Pages 起步——它简单、稳定、好调试。后续发现交互需求上来了,再迁移到 Blazor。反过来不行——从 Blazor 迁回 Razor Pages 我干过,重写的痛苦不想再来一次。
所以我的建议是:默认 Razor Pages,遇到 Blazor 主场场景时再用 Blazor。 这是增量引入,不是全量押注。
最后
选型这事没有银弹。Blazor 不是银弹,Razor Pages 也不是。能同时在一个项目里用两个,才是 .NET 全栈真正的优势。秦巴牧云的学费,希望帮你省点。
一句话总结:默认 Razor Pages,遇到实时看板/复杂交互/多步向导再上 Blazor Server,一个项目里混着用,共享 Domain 层。
你项目里用的是 Blazor 还是 Razor Pages?有没有踩过类似的坑?
转发给还在纠结选型的同事,少走我们趟过的弯路。
关注 CSharp精选营,每周二四 get 能直接抄的 C# 实战。
关于作者
码农刚子,六年 ERP / 制造业系统开发,专注 C# / .NET / Blazor。
博客:https://www.coderlog.net/ 公众号:CSharp精选营
暂无评论,来抢沙发吧~