[!TIP] 本页排查
dotnet new bitzorcas-host模板矩阵。bitz脚手架的故障排查见 bitz 交互式脚手架的已知限制与退出码章节。
当前 bitzorcas-host 是原生 dotnet new 模板。先定位失败阶段,再查看该阶段的输入和证据;不要把后续数据库或许可证问题归因于“模板没有生成”。
快速定位
先采集最小上下文:
# 只采集版本、模板注册和源键;不要输出凭据环境变量。dotnet --infodotnet new list bitzorcas-hostdotnet new bitzorcas-host --helpdotnet nuget list sourceHelp 没有模板或参数不对
找不到 bitzorcas-host
dotnet new install BitzOrcas.Modern.Templates@1.0.0-alpha1dotnet new list bitzorcas-host安装失败先解决 Feed。模板包与生成后商业依赖都来自授权 Feed,能访问 nuget.org 不代表能安装该包。
Help 与文档不同
卸载所有本机同 ID 版本,再安装精确版本:
dotnet new uninstall BitzOrcas.Modern.Templatesdotnet new install BitzOrcas.Modern.Templates@1.0.0-alpha1dotnet new bitzorcas-host --helpHelp 只应公开 ProfileChoice 与 RuntimeAdapter 两个 BitzOrcas 选择器。出现旧的拆分式业务选择器或内部 generated symbol,说明安装版本/包通道与本文不一致。
ProfileChoice 或 RuntimeAdapter 被拒绝
dotnet new 会在写入前校验 choice。当前 ORM 只有:
sqlsugarefcore
Profile 必须是参数参考列出的 15 个值之一。不要从基础词、租户词和扩展词自行拼接新值。
dotnet new bitzorcas-host -n Probe -o ./Probe \ --ProfileChoice default-business-single \ --RuntimeAdapter sqlsugarchoice 校验在写入任何文件之前完成。真实的拒绝效果——非法取值、模板引擎列出全部合法值、退出码 127、零写入:
如果上述基线命令失败,保留完整错误与 Help;不要通过修改模板缓存的 template.json 继续。
输出目录冲突或不完整
模板面向新目录。已有同名文件会触发冲突;强制覆盖可能留下旧项目和新文件混合的树。
# 使用系统临时目录,排除既有文件和仓库配置干扰。tmp_dir="$(mktemp -d)"dotnet new bitzorcas-host -n TemplateProbe -o "$tmp_dir/TemplateProbe" \ --ProfileChoice default-business-multi \ --RuntimeAdapter sqlsugar有效输出根至少有:
# 检查所有 Profile 都应具备的 Solution 与组合制品。root="$tmp_dir/TemplateProbe"test -f "$root/TemplateProbe.slnx"test -f "$root/composition-manifest.json"test -f "$root/composition-manifest.schema.json"test -f "$root/composition-plan.json"# Multi Profile 还必须具备 API 与 Architecture Tests 项目。test -d "$root/src/Hosts/TemplateProbe.Api"test -d "$root/tests/TemplateProbe.Architecture.Tests"Mini 没有 Starter Module/AppHost;Single Business 没有 AppHost;Multi Business 才有二者。当前公开模板没有 JobHost 或前端项目。
Manifest 与物理树不一致
先比较 manifest 和 plan:
# 先比较逻辑闭包,再列出实际项目文件。jq '{profileChoice, runtimeAdapter, hosts, projects}' \ composition-manifest.jsonjq '{selectedProjects, selectedEndpoints, selectedJobs}' \ composition-plan.jsonfind src tests -name '*.csproj' -print | sort常见原因:
- 在非空目录生成,旧文件未被模板管理;
- 生成后手工移动/删除项目;
- 本机安装的是旧模板,文档与安装包版本不同;
- 使用强制覆盖,导致客户文件和原生输出混合;
- 未审阅 Git 合并冲突。
恢复方法是在新空目录用同一名称、Profile、ORM 和精确版本重新生成,再用 Git/diff 迁移客户改动。不要手改 manifest/plan 让它们“匹配”错误的树。
Feed 与 Restore
先检查源键和 URL 是否存在,不输出凭据值:
dotnet nuget list sourcetest -n "$BITZORCAS_COMMERCIAL_FEED_URL"dotnet restore <Name>.slnx --no-http-cache --verbosity normal| 现象 | 优先判断 | 处理 |
|---|---|---|
BITZFEED001 | Feed URL 未注入 | 设置 BITZORCAS_COMMERCIAL_FEED_URL |
401/403、认证型 NU1301 | Credential Provider/Token | 核对源键大小写、到期、撤销和 CI Secret |
NU1101/NU1102 | entitlement/版本通道 | 核对包 ID、1.0.0-alpha1 通道与组织授权 |
NU3000 | 包签名策略 | 修复证书链、可信根或时间;禁止关闭验证 |
| 超时/DNS/TLS | 网络路径 | 检查代理、DNS、企业证书与 Feed 服务 |
日志可记录源键、包 ID、版本和 HTTP 状态,不能打印 NuGetPackageSourceCredentials_BitzOrcasCommercial 的值。
锁文件失败
CI 的 ContinuousIntegrationBuild=true 会启用 locked mode。先查看差异:
git diff -- '**/packages.lock.json' Directory.Packages.propsdotnet restore <Name>.slnx -p:RestoreLockedMode=falsegit diff -- '**/packages.lock.json'第二条命令只用于在受控升级分支更新候选锁文件。审阅版本、源与传递闭包后提交;不要在 CI 删除锁文件或长期关闭 locked mode。
Build 找不到类型或扩展方法
先确保 Restore 与 Build 使用同一 SDK、同一工作目录和同一锁文件:
dotnet --versiondotnet restore <Name>.slnxdotnet build <Name>.slnx --configuration Release --no-restore然后检查:
Directory.Packages.props是否被局部项目版本覆盖;- Profile 包与 Generator 包是否来自同一版本;
- 客户是否删除了生成属性、Module marker 或 Endpoint assembly;
- Source Generator 的编译诊断是否被前面的错误掩盖;
- 项目引用是否仍为 Host → Application → Contracts。
不要通过给 Application 添加 ORM/Host 引用来“修复”生成错误;这会转化为架构违规。
ORM 与命令选择不一致
# manifest、Host 注册和中央包版本必须指向同一 ORM。jq -r '.runtimeAdapter' composition-manifest.jsonrg -n 'SqlSugar|EfCore' \ src/Hosts/<Name>.Api/Program.cs \ src/Hosts/<Name>.Api/<Name>.Api.csproj \ Directory.Packages.propsSqlSugar 输出应注册 SqlSugar,EF Core 输出应注册 EF Core 并带 EF Schema contribution。若两套 Provider 同时出现或命令/manifest/代码不一致,从空目录重新生成并比较;不要只改 runtimeAdapter 文本。
Architecture Tests 失败
生成的架构测试是产品边界,不是示例噪声。常见违规:
- Consumer 复制 Framework/Platform 源码;
- Application 引用 ORM、Host 或基础设施实现;
- 为聚合建立平行 Entity/Mapper/DataPort;
- 业务不变量移到 Handler;
- Owner private 类型泄漏到公开合同;
- 手写 DI/Endpoint 绕过 Generator;
- Module 或 Host 项目引用越界。
dotnet test tests/<Name>.Architecture.Tests \ --configuration Release \ --logger 'console;verbosity=detailed'修复依赖方向或切片结构,不能删除/跳过测试作为长期处理。
Schema Migrator 失败
Single Profile 显式运行 Schema;Multi Profile 从 AppHost 启动同一 API 项目:
dotnet run --project src/Hosts/<Name>.Api -- \ --migrate-schema apply稳定退出边界:
| 退出码 | 含义 |
|---|---|
| 0 | 操作成功 |
| 1 | 执行异常 |
| 2 | action 缺失或无效 |
| 3 | ConnectionStrings:PrimaryDatabase 缺失 |
SqlSugar 当前采用显式 apply;EF Core 还可按生成 README 使用 plan/status/apply。Schema 模式不加载 JWT、Tenant、License 或 ServiceDefaults,因此这些错误不应阻塞迁移命令。
AppHost 中 API 一直未启动
这是 WaitForCompletion(schema-migrator) 的预期失败关闭行为。按顺序查看:
- SQL Server 容器是否健康;
PrimaryDatabase是否创建;schema-migrator日志与退出码;- Migration/DDL 是否有权限、冲突或不兼容;
- API 是否仍在等待迁移资源。
不要删除等待关系来获得“绿色”API;先修复 Schema。生产环境也要保持迁移成功先于新版本流量。
Host 启动期配置失败
| 错误/键 | 原因 |
|---|---|
ConnectionStrings:PrimaryDatabase | Business API 未取得数据库连接 |
Host.Persistence.Identity.Invalid | WorkerId 不在 1..31、DataCenterId 不在 0..31 或缺失 |
Authentication:Jwt:* | Issuer/Audience/SigningKey 缺失,Key 少于 32 bytes |
| 固定租户配置 | Single Business 的固定租户无效 |
Host.Licensing.Configuration.Invalid | 已启用 License 但配置闭包不完整 |
Multi AppHost 的 user-secrets 参数名是 Parameters:persistence-worker-id 和 Parameters:persistence-data-center-id。直接运行 API 时则提供 Persistence:WorkerId、Persistence:DataCenterId。
Authorization Profile 失败
Authorization 比中性 Business 多四类前置:
- RabbitMQ Host/User/Password/Port 或 Aspire
ConnectionStrings:rabbitmq; - Authorization persistence Provider 与 Host ORM 一致;
- 独立的 Authorization operations WorkerId/DataCenterId;
- bootstrap tenant 与 subject key。
Multi AppHost 的顺序为 Schema → authorization-bootstrap → API。任何一次性资源失败都会阻止 API。先看对应资源日志,不要把它当作普通 default-business-multi 排障。
Health 返回 503
三个端点不能互相替代:
| 路径 | 503 的主要范围 |
|---|---|
/health/live | 进程活性检查失败 |
/health/ready | 基础运行依赖未就绪 |
/health/license | Runtime License 缺失、过期、签名/策略/缓存失败 |
/health/ready 不会只因 License 缺失失败。发布平台若要求 License 门禁,应单独探测 /health/license 或组合两者。
Scalar/OpenAPI 无法访问
检查 OpenApi:Enabled、Environment 与访问保护:
curl -i http://localhost:<port>/openapi/v1.jsoncurl -i http://localhost:<port>/scalar/v1Development 默认启用;非 Development 默认不应假设开放。启用 RequireAuthentication 时,交互文档登录入口与 API Bearer 是不同认证面,详见 OpenAPI 与 Scalar。
验证确定性
怀疑模板漂移时,在两个空目录使用完全相同命令:
# 两次使用相同名称、Profile、ORM 和空目录。base="$(mktemp -d)"for n in one two; do dotnet new bitzorcas-host -n Deterministic -o "$base/$n" \ --ProfileChoice default-business-single \ --RuntimeAdapter efcoredone# 递归 diff 应无输出;任何差异都进入模板缺陷证据。diff -ru "$base/one" "$base/two"真实运行的确定性验证(两次生成后递归 diff,退出码 0 即逐字节一致):
有差异时记录模板包版本、SDK、OS 和完整命令,作为模板缺陷提交。无差异而业务仓库不同,继续调查手工修改、合并结果和旧文件。
安全证据包
提交问题前收集:
# 环境、Help 与源列表不含 Secret,可直接生成基础证据。dotnet --info > dotnet-info.txtdotnet new bitzorcas-host --help > template-help.txtdotnet nuget list source > nuget-sources.txt# 组合摘要与 Build 日志发送前仍需执行敏感信息扫描。jq '{profileChoice,runtimeAdapter,hosts,projects}' \ composition-manifest.json > composition-summary.jsondotnet build <Name>.slnx --configuration Release \ --verbosity normal > build.log 2>&1发送前扫描 Token、连接串、JWT Key、License、用户目录和内部 URL。优先提供错误前后有限日志、退出码、精确 Commit/模板版本和可复现命令。