来源：https://framework.docs.xihanfun.com/guide/faq

# 常见问题

本页收集使用框架时最常遇到的问题与排查方法，按装配、操作与协议、数据与安全、版本与能力范围分组。

## 装配

### 启动时报 KERNEL_CAPABILITY_004，说某个能力有多个候选

同一能力有两个以上显式 Provider，内核无法替应用选择。在配置里指定提供者，或在代码里调用 `UseProvider`：

```json
{ "XiHan": { "Providers": { "caching.distributed": "xihan.caching.redis" } } }
```

清单 ID 写在各包页的信息表里；规则见[能力包与清单](./modularity#选择-provider)。

### 启动时报 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>()` 声明次序，不能依赖归属字典序。见[执行管道](./pipeline#排序规则)。

### 怎样查看最终的能力图谱与管道顺序

启动日志在 Information 级别打印两者。接了命令行宿主时运行 `graph` 与 `pipeline` 命令；代码里用 `App.DescribeGraph()` 与 `App.DescribePipeline()`。

## 操作与协议

### 编译报 XHG002

操作的请求或响应类型没有登记到任何 `JsonSerializerContext`。在项目的序列化上下文上加 `[JsonSerializable(typeof(...))]`，见[操作契约](./operations#登记序列化类型与-schema)。

### 操作没有出现在 HTTP 路由或 OpenAPI 里

逐项检查：

1. 特性的 `Configure` 调用了 `context.AddGeneratedOperations()`，项目引用了 `Kernel.Generators`（以分析器方式）。
2. 操作的 `Expose` 包含 `Expose.Http`；没写 `Expose` 时看程序集级 `OperationDefaults`。
3. 操作的 `Stability` 不是 `Internal`。
4. 应用加入了 `HttpProtocolFeature`，并在 `app.UseXiHan()` 之后调用了 `app.MapXiHanOperations()`。

### 两个操作启动时报 PROTOCOLS_CONFLICT_002

两个操作推导出了同一条 HTTP 路由或同一个 gRPC 方法名，典型情况是请求都不含 `id` 的 `get` 与 `list`。按操作覆盖其中一条路由，见 [HTTP 与 OpenAPI](./http)。

### 调用返回 503 与 KERNEL_UNAVAILABLE_001

应用还没有就绪或正在停止。看 `/health/startup` 与 `/health/ready` 的响应，找出状态不是 `Ready` 的特性；启动失败的原因记录在启动日志里。

### 返回 503 与 KERNEL_UNAVAILABLE_002、003 或 004

分别是限流、并发上限与熔断拒绝，来自 `XiHan:Kernel:Resilience` 的配置。响应的 `details.retryAfter` 给出建议的重试秒数，见[弹性与限流](./resilience)。

### Problem Details 的 detail 总是英文

宿主按请求头 `Accept-Language` 选择区域，没有指定时用默认区域 `en-US`。应用自己的消息键要在对应语言的 `Localization/<区域>.json` 里有译文，并用 `AddMessageCatalog` 登记目录，见[国际化](./localization)。

### 什么时候是 401，什么时候是 403

`SECURITY_DENIED_001`（未认证）与 `SECURITY_DENIED_003`（凭据无效、过期或签名不符）是 401，并带 `WWW-Authenticate` 质询；已认证但缺少权限（`SECURITY_DENIED_004`）或被策略拒绝（`SECURITY_DENIED_002`）是 403。

## 数据与安全

### 在后台任务里使用仓储报 PERSISTENCE_UNAVAILABLE_001

仓储只能在活动的工作单元内使用。操作调用由 Transaction 阶段自动开启工作单元；管道之外（后台循环、`IHostedFeature.StartAsync`、单例服务）要自己创建作用域并开启工作单元，写法见[工作单元与事务](./uow)。

### 重启后内存里的数据都没了

`Persistence.InMemory` 是开发与测试用的默认实现，数据只在进程内且容量有界。生产环境加入 `Persistence.EntityFrameworkCore` 或 `Persistence.SqlSugar`。

### 新增多租户实体时报 PERSISTENCE_VALIDATION_001

实体实现了 `IMultiTenant`，但当前调用没有租户。检查认证主体是否带租户声明、调用方是否在 Baggage 里给出租户，或把配置 `XiHan:MultiTenancy:RequireTenant` 打开，让没有租户的调用在 Tenant 阶段就被拒绝，见[多租户](./multi-tenancy)。

## 版本与能力范围

### 框架能用于生产吗

框架还在预览阶段，公开面多数标为 `Preview` 或 `Experimental`，正式版前仍可能调整。评估与新项目试点可以使用；需要稳定版本的生产系统等正式版。

### 框架不提供哪些能力

下列能力不由框架包装，原因是它们属于应用层需求，或 .NET 与成熟的专门组件已经覆盖。开发指南不为它们设章节。

| 能力 | 做法 |
| --- | --- |
| 机器人与消息通知渠道（邮件、短信、Telegram、钉钉、飞书、企业微信） | 应用直接使用各渠道的 SDK 或 HTTP 接口，封装成应用自己的服务；需要异步发送时经消息子系统投递。`Messaging` 是队列、流与发布订阅子系统，不是通知渠道 |
| 实时通信（SignalR 封装） | 直接使用 ASP.NET Core SignalR，Hub 的认证经 `XiHan` 认证方案交给内核，见[实时通信](./realtime) |
| 网关与流量治理 | 反向代理与转发用 YARP 等专门组件；按操作的熔断、限流、并发上限由内核的 Resilience 阶段提供，见[弹性与限流](./resilience) |
| 模板引擎 | 直接使用 Scriban、Fluid 等模板库 |
| 脚本引擎 | 不提供。需要隔离执行第三方逻辑时用插件，见[插件](./plugins) |
| 搜索引擎 | 直接使用 Elasticsearch、OpenSearch 等的官方客户端 |
| HTTP 客户端封装 | 使用 `IHttpClientFactory` 与 `Microsoft.Extensions.Http.Resilience` |
| 数据加解密 | 使用 `System.Security.Cryptography` 与 ASP.NET Core Data Protection。`Security` 是认证与授权子系统 |
| 对象映射 | 显式映射，或编译期生成代码的映射库，见[序列化与 Native AOT](./aot#对象映射) |
| 序列化封装 | 直接使用 System.Text.Json 的源生成上下文 |
| 虚拟文件系统 | 使用 .NET 的 `IFileProvider` 与嵌入资源 |
| 设置 | 使用 .NET 配置与 `IOptionsMonitor`，远程配置见[配置与选项](./configuration) |
| 声明式缓存特性 | 不提供，用 `ICacheStore`、`ICache`、`ISharedCache` 显式读写，见[缓存与分布式锁](./caching) |
| 版本升级编排 | 由应用实现，需要单点执行时用调度子系统的领导选举 |
| 开发工具 | 命令行宿主的 `graph`、`pipeline`、`operations`、`invoke` 与 `xihan` 工具，见[命令行宿主](./command-line) |
