为什么选择曦寒
本页是选型说明:XiHan Framework 适合什么项目、换来什么、付出什么,以及在当前预览阶段的限制。适合正在评估后端框架的团队阅读。
结论
| 情况 | 建议 |
|---|---|
| 中大型、长期维护、多人协作的 .NET 后端,重视依赖边界与可替换性 | 适合 |
| 多租户 SaaS、企业中后台,需要租户、权限、审计、工作流、调度这类通用能力 | 适合 |
| 同一业务要同时提供 REST、gRPC、MCP tool 或命令行 | 适合 |
| 需要第三方用其他语言写插件,或要求插件崩溃不拖垮宿主 | 适合 |
| 目标是 Native AOT 发布或冷启动敏感的服务 | 适合,非 AOT 的 Provider 需替换或接受 JIT |
| 短期项目,只要几个 CRUD 接口 | 直接用 ASP.NET Core 最小 API 更省事 |
| 必须马上上生产、需要 nuget.org 上的正式版 | 框架仍是预览,见下文「当前限制」 |
它解决的问题
装配可检查
多数模块化框架把依赖写在特性或基类上,依赖关系要到运行时才知道。这里每个特性带一份清单,按能力 ID 声明依赖:
text
xihan.persistence.inmemory <版本> (default)
provides persistence.relational@1
requires kernel.hosting@1 -> xihan.kernel.core内核在构建期求解全部清单,缺失依赖、循环、版本冲突、同一能力多个候选都会带着双方信息报错;启动日志与 graph 命令打印同一份已解析图。同一能力有多个 Provider 时,选择写在配置 XiHan:Providers:<能力 ID> 里,不靠注册顺序。
横切逻辑有固定位置
认证、租户、授权、校验、幂等、事务分别落在管道的固定阶段,任何协议进来的调用都经过同一条管道。中间件只关心自己的阶段,顺序由「阶段 → 约束 → 归属」确定并可打印,不依赖动态代理。
一份契约,多种协议
操作以 [Operation] 声明一次,源生成器产出 JSON Schema。HTTP 路由、OpenAPI 文档、gRPC 的 .proto、MCP 的 tool 描述、命令行参数都由同一份契约推出,授权要求与错误码在各协议上一致。
默认实现与 Provider 分离
每个子系统的抽象都有一个零外部依赖、容量有界的默认实现,开发与测试不需要数据库、Redis 或消息代理。上线时加 Provider 包与一行 UseFeature,默认实现自动让位;Provider 与默认实现通过同一套一致性套件,行为差异在套件里可见。
边界由机器执行
依赖方向、包 ID 文法、命名空间、零反射、第三方类型泄漏、XML 文档、消息键与语言文件的一致性都由架构测试与分析器执行,不靠代码评审记忆。
换来的代价
| 代价 | 说明 |
|---|---|
| 写法更显式 | 每个特性要写清单;服务、权限、操作、消息处理器都要在 Configure 里显式登记,源生成器的登记也要显式调用 |
| 序列化要源生成 | 操作的请求与响应、领域事件的载荷要登记到 JsonSerializerContext;操作的类型没有登记时生成器报 XHG002 |
失败用 Result 表达 | 仓储、缓存、消息等端口返回 Result 而不是抛异常,调用方要处理失败分支 |
| 文案不写在代码里 | 面向人的文字以消息键引用,每个键要在 10 个语言文件里各有一行 |
| 概念更多 | 能力 ID、清单、管道阶段、操作契约、协议适配器是新概念,团队需要时间统一认识 |
当前限制
- 当前只有预览版,安装要带
--prerelease,见快速上手。 - 公开面多数标为
Preview或Experimental,正式版前仍可能调整。 - 框架不提供机器人、消息通知渠道、模板引擎、脚本引擎、搜索引擎、HTTP 客户端封装、网关、SignalR 封装、对象映射,替代做法见常见问题。
- Provider 覆盖面以包总览列出的为准:持久化有 EF Core 与 SqlSugar,没有 MongoDB;远程配置有 Nacos,没有 Apollo 与 Vault;对象存储有文件系统与 S3 兼容服务。
用最小成本验证
- 按快速上手写一个操作,确认装配、管道与 Problem Details 的行为。
- 运行仓库里的
framework/samples/SimpleApp:同一份订单契约同时在 HTTP、gRPC、MCP 上服务,入站 CloudEvents 经管道交给消息处理器,带租户、ApiKey 认证、权限、事务与发件箱,零外部设施。 - 把其中一个默认实现换成团队要用的 Provider(如
Persistence.EntityFrameworkCore或Caching.Redis),确认业务代码不需要改。
