常见问题
本页收集使用框架时最常遇到的问题与排查方法,按装配、操作与协议、数据与安全、版本与能力范围分组。
装配
启动时报 KERNEL_CAPABILITY_004,说某个能力有多个候选
同一能力有两个以上显式 Provider,内核无法替应用选择。在配置里指定提供者,或在代码里调用 UseProvider:
{ "XiHan": { "Providers": { "caching.distributed": "xihan.caching.redis" } } }清单 ID 写在各包页的信息表里;规则见能力包与清单。
启动时报 KERNEL_CAPABILITY_001,说依赖没有提供者
某个特性的 Requires 里有一个必需能力,但应用没有加入任何提供它的特性。错误信息给出需求方与能力 ID,加入对应的默认实现或 Provider(UseFeature<...>())即可;不需要它时把依赖标为可选。
引用了 Provider 包,但运行时仍在用内存实现
只引用包不会生效,还要在 AddXiHan 里 UseFeature<...>() 加入它的特性。加入后看启动日志里的能力图谱:被顶替的默认实现不再出现在该能力下,完全没有被选中的节点不装配。
中间件第一次调用时报「没有注册服务」
用 AppBuilder.ConfigurePipeline 或 Pipeline.UseAt<T> 登记的中间件,内核不替应用注册类型,需要自己 builder.Services.AddSingleton<T>()。在特性里用 context.AddMiddleware<T>() 登记则由内核一并注册。
中间件里取不到主体或租户
主体在 Authenticate 阶段、租户在 Tenant 阶段之后才写入上下文。中间件要放在这些阶段之后;同一阶段内依赖另一个包中间件的产出时,必须用 After<TMiddleware, TOther>() 声明次序,不能依赖归属字典序。见执行管道。
怎样查看最终的能力图谱与管道顺序
启动日志在 Information 级别打印两者。接了命令行宿主时运行 graph 与 pipeline 命令;代码里用 App.DescribeGraph() 与 App.DescribePipeline()。
操作与协议
编译报 XHG002
操作的请求或响应类型没有登记到任何 JsonSerializerContext。在项目的序列化上下文上加 [JsonSerializable(typeof(...))],见操作契约。
操作没有出现在 HTTP 路由或 OpenAPI 里
逐项检查:
- 特性的
Configure调用了context.AddGeneratedOperations(),项目引用了Kernel.Generators(以分析器方式)。 - 操作的
Expose包含Expose.Http;没写Expose时看程序集级OperationDefaults。 - 操作的
Stability不是Internal。 - 应用加入了
HttpProtocolFeature,并在app.UseXiHan()之后调用了app.MapXiHanOperations()。
两个操作启动时报 PROTOCOLS_CONFLICT_002
两个操作推导出了同一条 HTTP 路由或同一个 gRPC 方法名,典型情况是请求都不含 id 的 get 与 list。按操作覆盖其中一条路由,见 HTTP 与 OpenAPI。
调用返回 503 与 KERNEL_UNAVAILABLE_001
应用还没有就绪或正在停止。看 /health/startup 与 /health/ready 的响应,找出状态不是 Ready 的特性;启动失败的原因记录在启动日志里。
返回 503 与 KERNEL_UNAVAILABLE_002、003 或 004
分别是限流、并发上限与熔断拒绝,来自 XiHan:Kernel:Resilience 的配置。响应的 details.retryAfter 给出建议的重试秒数,见弹性与限流。
Problem Details 的 detail 总是英文
宿主按请求头 Accept-Language 选择区域,没有指定时用默认区域 en-US。应用自己的消息键要在对应语言的 Localization/<区域>.json 里有译文,并用 AddMessageCatalog 登记目录,见国际化。
什么时候是 401,什么时候是 403
SECURITY_DENIED_001(未认证)与 SECURITY_DENIED_003(凭据无效、过期或签名不符)是 401,并带 WWW-Authenticate 质询;已认证但缺少权限(SECURITY_DENIED_004)或被策略拒绝(SECURITY_DENIED_002)是 403。
数据与安全
在后台任务里使用仓储报 PERSISTENCE_UNAVAILABLE_001
仓储只能在活动的工作单元内使用。操作调用由 Transaction 阶段自动开启工作单元;管道之外(后台循环、IHostedFeature.StartAsync、单例服务)要自己创建作用域并开启工作单元,写法见工作单元与事务。
重启后内存里的数据都没了
Persistence.InMemory 是开发与测试用的默认实现,数据只在进程内且容量有界。生产环境加入 Persistence.EntityFrameworkCore 或 Persistence.SqlSugar。
新增多租户实体时报 PERSISTENCE_VALIDATION_001
实体实现了 IMultiTenant,但当前调用没有租户。检查认证主体是否带租户声明、调用方是否在 Baggage 里给出租户,或把配置 XiHan:MultiTenancy:RequireTenant 打开,让没有租户的调用在 Tenant 阶段就被拒绝,见多租户。
版本与能力范围
框架能用于生产吗
框架还在预览阶段,公开面多数标为 Preview 或 Experimental,正式版前仍可能调整。评估与新项目试点可以使用;需要稳定版本的生产系统等正式版。
框架不提供哪些能力
下列能力不由框架包装,原因是它们属于应用层需求,或 .NET 与成熟的专门组件已经覆盖。开发指南不为它们设章节。
| 能力 | 做法 |
|---|---|
| 机器人与消息通知渠道(邮件、短信、Telegram、钉钉、飞书、企业微信) | 应用直接使用各渠道的 SDK 或 HTTP 接口,封装成应用自己的服务;需要异步发送时经消息子系统投递。Messaging 是队列、流与发布订阅子系统,不是通知渠道 |
| 实时通信(SignalR 封装) | 直接使用 ASP.NET Core SignalR,Hub 的认证经 XiHan 认证方案交给内核,见实时通信 |
| 网关与流量治理 | 反向代理与转发用 YARP 等专门组件;按操作的熔断、限流、并发上限由内核的 Resilience 阶段提供,见弹性与限流 |
| 模板引擎 | 直接使用 Scriban、Fluid 等模板库 |
| 脚本引擎 | 不提供。需要隔离执行第三方逻辑时用插件,见插件 |
| 搜索引擎 | 直接使用 Elasticsearch、OpenSearch 等的官方客户端 |
| HTTP 客户端封装 | 使用 IHttpClientFactory 与 Microsoft.Extensions.Http.Resilience |
| 数据加解密 | 使用 System.Security.Cryptography 与 ASP.NET Core Data Protection。Security 是认证与授权子系统 |
| 对象映射 | 显式映射,或编译期生成代码的映射库,见序列化与 Native AOT |
| 序列化封装 | 直接使用 System.Text.Json 的源生成上下文 |
| 虚拟文件系统 | 使用 .NET 的 IFileProvider 与嵌入资源 |
| 设置 | 使用 .NET 配置与 IOptionsMonitor,远程配置见配置与选项 |
| 声明式缓存特性 | 不提供,用 ICacheStore、ICache、ISharedCache 显式读写,见缓存与分布式锁 |
| 版本升级编排 | 由应用实现,需要单点执行时用调度子系统的领导选举 |
| 开发工具 | 命令行宿主的 graph、pipeline、operations、invoke 与 xihan 工具,见命令行宿主 |
