Healnet.Infrastructure 6.0.0

dotnet add package Healnet.Infrastructure --version 6.0.0
                    
NuGet\Install-Package Healnet.Infrastructure -Version 6.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Healnet.Infrastructure" Version="6.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Healnet.Infrastructure" Version="6.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Healnet.Infrastructure" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Healnet.Infrastructure --version 6.0.0
                    
#r "nuget: Healnet.Infrastructure, 6.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Healnet.Infrastructure@6.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Healnet.Infrastructure&version=6.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Healnet.Infrastructure&version=6.0.0
                    
Install as a Cake Tool

Healnet.Infrastructure 基础设施层

版本: 5.0.0 | 依赖: Healnet.Core → Healnet.Common | TFM: net10.0 | License: MIT

Healnet.Infrastructure 是 Healnet 微服务框架的基础设施实现层:对 26 个中间件/基础设施组件提供统一封装与 DI 注册约定,实现 Healnet.Core 定义的抽象契约(ICacheService、IUnitOfWork、ITokenService、IHttpClientService、IConsulService、ISessionChatClient 等)。契约在 Core、实现在本层(DIP);AI 抽象位于 Healnet.Core.AI / Healnet.Core.AI.Memory,本层 AI/ 仅含实现。

安装与最小接入

dotnet add package Healnet.Infrastructure
// Program.cs —— 业务服务推荐的两行入口(Service Defaults)
builder.AddHealnetServiceDefaults();   // 日志 / Consul / gRPC 转码 / MVC / JWT / 健康检查 / Swagger / Kestrel
// ...
app.UseHealnetServiceDefaults();       // 请求日志 → 全局异常 → CorrelationId → 认证授权 → 端点映射 → Consul 注册

按需细粒度接入时,各模块独立 AddXxx(见下表),配置节点统一约定在 Healnet:<模块>。

模块目录

模块 一句话定位 README
Extensions 聚合注册入口 + Service Defaults(推荐接入点) Extensions/README.md
Authentication JWT 令牌 + API Key 认证 Authentication/README.md
Security 安全响应头 + CORS Security/README.md
SqlSugar ORM:多库连接 + 泛型仓储 SqlSugar/README.md
UnitOfWork SqlSugar 事务工作单元 UnitOfWork/README.md
MongoDB 多租户文档数据库 MongoDB/README.md
ElasticSearch NEST 全文搜索封装 ElasticSearch/README.md
Milvus 向量数据库(ANN 检索) Milvus/README.md
Redis 分布式缓存 + Lua 分布式锁 Redis/README.md
RabbitMQ 消息队列(发布/订阅/死信) RabbitMQ/README.md
OSS 阿里云对象存储(IFileService 实现) OSS/README.md
Consul 服务注册/发现/健康检查 Consul/README.md
Http HttpClient + Polly 弹性 + Consul 发现 Http/README.md
YARP API 网关(静态路由/Consul 动态发现) YARP/README.md
gRPC 通道缓存 + 强类型客户端封装 gRPC/README.md
Logging Serilog 结构化日志 Logging/README.md
OpenTelemetry Tracing/Metrics/Logging 三件套 OpenTelemetry/README.md
HealthChecks 多组件健康检查(统一 JSON) HealthChecks/README.md
Middleware 请求日志 / 关联 ID 中间件 Middleware/README.md
Resilience Polly 重试/熔断/限流策略 Resilience/README.md
AOP AspectCore 内置拦截器族 AOP/README.md
Swagger API 文档(含 gRPC Transcoding 文档) Swagger/README.md
AI MEAI 统一会话链路 + 记忆分层 AI/README.md
Skill Skill 模板加载/解析/渲染(一句话 README) Skill/README.md
Helpers gRPC 客户端 IP 提取等静态助手(一句话 README) Helpers/README.md
Mvc 模型校验统一 ApiResponse(一句话 README) Mvc/README.md

gRPC 客户端完整调用案例(多层嵌套消息 / 流式 / Swagger JSON 对照)见 Swagger/GRPC_EXAMPLE.md。

版本策略

  • 三库(Common / Core / Infrastructure)统一版本号发布;PackageReleaseNotes 逐版本记录缺陷修复与兼容性说明,历史明细用 git log 追溯。
  • 破坏性变更集中在主版本(3.0 / 5.0);4.x 内的 DI 生命周期调整等行为变化均在该版本 ReleaseNotes 中显式标注兼容性。

架构约定(精简版)

  • 契约在 Core,实现在 Infrastructure:本层各模块 README 顶部均标注对应的 Core 抽象来源。
  • OSS 替换 Common 的 IFileService:AddAliyunOssFileService 经 services.Replace 切换实现。
  • 过时成员已标 [Obsolete]:如 Middleware 的 UseExceptionHandling / UseHealthCheck,替代指引见各模块 README「⚠️ 常见坑」。
  • 各模块 README 只保留「快速上手」:一句话定位 + 3 步接入 + 最小配置 + 常见坑;API 签名细节看代码 IntelliSense(包内随带 XML 注释)。
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
6.0.0 0 11/5/2026
5.3.0 0 11/5/2026
5.2.0 0 11/5/2026
5.1.1 0 11/5/2026
5.1.0 0 11/5/2026
5.0.0 6 11/4/2026
4.0.40 41 11/4/2026
4.0.39 42 11/4/2026
4.0.38 46 11/3/2026
4.0.37 44 11/3/2026
4.0.36 43 11/3/2026
4.0.35 47 11/3/2026
4.0.34 40 11/3/2026
4.0.33 43 11/3/2026
4.0.32 39 11/3/2026
4.0.31 42 11/3/2026
4.0.30 43 11/3/2026
4.0.27 42 11/3/2026
4.0.26 40 11/3/2026
4.0.25 44 11/3/2026
Loading failed

v6.0.0: 破坏性批次(BREAKING:删除到期废弃中间件 + API 收敛)。① 移除 [Obsolete] 到期的旧中间件(全生态零引用实证:src/tests/examples + 5 个消费方仓库):ExceptionHandlingMiddleware(旧异常中间件)、HealthCheckMiddleware(旧健康检查中间件,请用 app.MapHealthChecks("/health"))、MiddlewareExtensions.UseHealthCheck 扩展(引用被删类)。保留 app.UseExceptionHandling()——它是 Core ExceptionHandlerMiddleware 的便捷包装,healnet.server 8 服务 + agentos 2 仓共 10 处活跃调用,README 原先误标 Obsolete 已修正。② API 收敛:7 处 UsageExample 空壳占位类 public→internal。依赖:Healnet.Core 6.0.0 / Healnet.Common 5.0.0。 v5.3.0: SqlSugar 封装审查优化批(P2 四项 + 过程中实证发现的 P1 一项)。① 【P1】SqlSugarRepository.GetClient 走「子对象租户链」的调度依赖崩溃修复:原实现 base.Context.AsTenant().GetConnectionScope(resolved),反编译 SqlSugarCore 5.1.4.215 实证 SqlSugarProvider.AsTenant() 在 Root==null 时无条件抛「Child objects do not support tenant methods」(Root 仅在 master SqlSugarClient 经 GetConnection 创建 provider 时赋值;SqlSugarScopeProvider 的上下文存储为每次调用 StackTrace 扫描 + ThreadLocal(CallContextThread)/AsyncLocal(CallContextAsync) 混合 + GetKey 线程身份 key 复用——跨线程/异步上下文自动新建的 provider 不带 Root),该缺陷随线程/上下文调度时好时坏(既有 SqlSugarIntegrationTests 的手工转移注册形态恰好命中安全路径而掩盖);现改为与构造函数同走 master 链(持有 _masterClient,SqlSugarClient.AsTenant() 恒返回自身、GetConnectionScope 恒设 Root——均反编译确认),链路确定安全;变异证伪:改回子对象链 → 生产容器形态(AddSqlSugar 直建 + CreateScope)分页用例稳定抓红。② 仓储分页改官方 RefAsync 模式:两个 PageAsync 重载原实现 CountAsync 后复用同一 queryable 实例(可变 builder,脆弱),改 ToPageListAsync(pageIndex, pageSize, RefAsync<int>) 内部 count+取数,TotalCount / PageModel.TotalCount 背传语义不变。③ 新增慢 SQL 监控:ConfigureAop 挂 Aop.OnLogExecuted,经 Ado.SqlExecutionTime 取真实耗时,每条记 Debug([SQL] {耗时}ms | {SQL},不记参数值同 LogExecuting 脱敏约定);新配置 Healnet:SqlSugar:SlowQueryThresholdMs(默认 1000,≤0 关闭升级),达阈值升 Warning([SlowSQL] 前缀);行为体抽 internal LogExecuted 共享(与 LogExecuting 同一组合契约——AopProvider 委托只写无 get),与 5.2.0 审计日志(只组合 OnLogExecuting)正交不冲突。④ AddSqlSugar 重复注册防护:RegisterSqlSugar 统一入口检测 ISqlSugarClient 已注册即抛带修复指引异常(原二次调用静默新建 Scope 覆盖,DI last-wins,多模块/测试场景易产生难排查的路由错乱)。⑤ PagedResult.TotalPages 除零防护:PageSize<=0 或 TotalCount<=0 返回 0(原 (int)Infinity 抛 OverflowException)。新增守卫测试 SqlSugarSlowSqlGuardTests 9 项(重复注册 1 + LogExecuted 阈值 sink 断言 3 + TotalPages 边界 3 + 生产容器形态分页回归 2),SqlSugar 全套 28/28 绿、变异证伪 GetClient 子对象链 2/2 抓红。README 同步 SlowQueryThresholdMs 与重复注册说明。仅本包变更,依赖 Core 5.1.0 不变。 v5.2.0: P2 能力批 —— Consul KV 配置中心(动态刷新)+ SqlSugar 审计日志(CUD → Serilog → ES)。① Consul/ConsulKVExtensions:AddHealnetConsulKV 在 IConfigurationBuilder 上挂 Consul KV 配置源(Winton.Extensions.Configuration.Consul 3.4.0,MIT,新增依赖);设计红线——只挂 ConfigurationSource 完全不碰 DI 注册(与 AddConsul 正交无双注册)、KV 根键未配置完全不启用(no-op)、Optional=true(默认)Consul 不可达启动不崩、ReloadOnChange=true watch 动态刷新(⚠️ 仅运行时读取生效,SqlSugarOptions 等启动快照进 Singleton 的配置不随刷新传播需重启,已文档化)。② SqlSugar/AuditLog/:AuditLogCollector 经 Aop.OnLogExecuting 语句级拦截 DML(回调次数=SQL 数,无每行每列放大)——⚠️ SqlSugar AopProvider 委托只写无 get,组合经共享行为体 SqlSugarExtensions.LogExecuting 实现(框架 SQL Debug 日志语义保留);参数按名脱敏(黑名单 password/token/idcard/mobile 等,匿名参数 @p0 无法按名判断已文档化);有界 Channel(满载显式容量检查丢弃计数,.NET 10 DropWrite 下 TryWrite 返回值不可靠)后台批量写 Serilog——复用既有 Serilog.Sinks.OpenSearch 管道落 ES(独立索引按 SourceContext "Healnet.AuditLog" 路由),零新增 sink 依赖、绝不阻塞 CUD 线程;AddHealnetAuditLog 默认 Enabled=false 零注入(不注册服务不挂 Aop)。③ CPM:Serilog 浮动下限 [4.0.0,)→[4.3.0,)(Serilog.AspNetCore 10.0.0 传递要求,消 NU1605)。新增 24 项守卫测试(ConsulKVTests 6 + AuditLogTests 18),变异证伪 4/4 抓红。依赖 Core 5.1.0 不变。 v5.1.1: 热修 SqlSugarOutboxStore 多库连接名边缘 bug。① 缺陷:EventBus 的 SqlSugarOutboxStore.GetConnectionScope(OutboxDbName) 字面量直查——多库且首连接名非 "Default"、又未显式配 OutboxDbName(默认占位 "Default")的消费方,OutboxProcessor 启动后即抛「ConfigId was not found Default」(与 SqlSugarRepository v4.0.31 修复前的同源缺陷)。② 修复:解析逻辑抽到共享的 SqlSugarConnectionResolver(internal,经 InternalsVisibleTo 供守卫测试断言)——占位默认值 "Default" 在连接配置中不存在时回退首个 ConfigId(对齐仓储 v4.0.31 别名映射语义);显式配置的连接名保持直查/不存在时 fail-fast(防静默改路由);空配置视同未配置。③ SqlSugarRepository.ResolveDefaultDbName 改为调用共享实现,行为不变(守卫测试回归保护)。新增 8 项守卫测试(SqlSugarConnectionResolverTests),变异证伪 2/2 抓红。仅本包变更,依赖 Core 5.1.0 不变。 v5.1.0: 第一梯队能力批(事件总线闭环 + Cron 后台任务 + 自动 DI)。① Background/:CronBackgroundService——Cronos 调度、优雅停机、单次失败吞掉记日志(宿主不死)、重叠保护(TryExecuteOnceAsync 跳过语义)、时区换算、AddCronJob 注册;新增 Cronos 0.13.0 依赖。② EventBus/:InMemoryEventDispatcher(救活 Core 的 IDomainEventDispatcher 死契约,按运行时类型路由、单处理器失败继续)、SqlSugarOutboxStore+OutboxEntityMapper(救活 IOutboxStore,表 outbox_message,失败指数退避 2^n 秒封顶 300s、超限 DeadLetter)、OutboxEventBus(IEventBus 实现,进程内分发 + 集成事件 Web(camelCase) 序列化写箱)、OutboxProcessor(后台轮询投递,JsonElement 原样透传无双重编码,公开 ProcessPendingAsync 测试钩子)、InboxGuard(复用 IIdempotencyStore SETNX 语义,WithInbox 包装订阅处理器)、EventBusExtensions(AddEventBus/AddOutboxProcessor)。③ Extensions/AutoDIExtensions:AddHealnetAutoDIServices 按标记接口扫描注册(TryAdd 幂等、多标记取最高生命周期、泛型/抽象/编译器生成类型跳过)。依赖 Core 5.1.0。 v5.0.0: 5.0 契约 2.0 正式版(BREAKING,双 provider 收敛为唯一 MEAI 路径)。① 新增 SessionChatClient 会话装饰器(复用 ChatSessionStore:租约 API AcquireAsync/SessionLease 门横跨流枚举期、SessionEvicted 淘汰事件、IsSessionLive)与 NullSessionChatClient(未配 ApiKey 降级注册、调用时抛配置指引,与 NullCopilotClient 同范式);AddAIServices 统一注册 ISessionChatClient(单例),MicrosoftAI 分支复用已注册 IChatClient、SK 分支经共享工厂 CreateMeaiChatClient 直连 OpenAI 兼容端点;AIOptions 推理参数正式接线(随 Core 5.0.0)。② BREAKING 删除 Legacy/ 隔离区整目录 7 实现:UnifiedAIService/AgentService/AgentContextManager/ChatContextManager/RAGService/CopilotClient(SK)/LegacyChatHistory。③ 改名:MicrosoftAIClient → CopilotClient(ICopilotClient 唯一实现)。④ AI 目录按功能拆分:Chat/Copilot/Legacy(已删)/Memory,Chat 与 Copilot 命名空间保持 Healnet.Infrastructure.AI(消费方 using 零变化)。⑤ DX:26 模块 README 精简为「定位+快速调用」,目录按功能拆子目录(gRPC Client/Exceptions、Swagger Filters/Grpc、AOP Interceptors、HealthChecks Checks、Redis Services),namespace 全部不动。依赖 Core 5.0.0。 v4.0.40: AI 层架构评审兼容修复批(随 Core 4.0.15 的 [Obsolete] 标注,评审结论见 AI/README.md 文件职责表)。① AgentService 失败路径同样删除上下文:原仅成功后删除,而执行链路当前恒抛 NotSupportedException,等于每次调用泄漏一个 AgentContext(1h TTL 兜底);失败路径的排查依据改由异常本身承担。② RegisterAgentAsync/RegisterToolAsync 同名注册由 TryAdd 改为覆盖:原实现把运行时注册的同名 Agent/Tool 静默挡掉(默认内置项反而不可替换)。③ CopilotClient/MicrosoftAIClient 会话裁剪移到消息追加之后,修复 off-by-one:原实现先裁剪再追加,发送给模型的历史可达 单会话上限+1 条(守卫测试断言由 [1,3,3] 修正为 [1,2,2]);保存前再裁一次,内存持久历史同样不超过上限;单会话上限下限钳制为 2(一轮对话至少 user+assistant 两条)。④ 遗留兼容类型 ChatHistory/ChatHistoryRole 从 MicrosoftAIClient.cs 拆分至独立文件 LegacyChatHistory.cs 并随 Core 4.0.15 语义标 [Obsolete](框架内部零消费,5.0 删除)。⑤ SK 分支 HttpClient 由手工 new 统一走 IHttpClientFactory(命名客户端 Healnet.SemanticKernel + SetHandlerLifetime(InfiniteTimeSpan)——Kernel 单例长期持有该客户端,禁用 handler 轮换防捕获已处置 handler),与 EmbeddingService 模式对齐。⑥ 实现侧对废弃成员的链路内调用(AgentService.ChatAsync→ExecuteAsync、UnifiedAIService 转发)以 #pragma CS0618 显式抑制并注明 5.0 随类删除。依赖 Core 4.0.15。 v4.0.39: AI 服务面快修批(P1)+ 接入便利性。① IAgentService 注册由 Scoped 改为 Singleton:AgentService 内部维护随实例持久的注册表(_agents/_tools,构造时 InitializeDefaultAgents(),并公开 RegisterAgentAsync/RegisterToolAsync 运行时注册),Scoped 会导致每个请求重跑默认初始化、运行时注册的 Agent/Tool 下个请求即蒸发——与 RAGService 空知识库(4.0.37)、ICopilotClient 有状态(4.0.38)同类缺陷;其构造依赖 AIOptions 与 IAgentContextManager 均为单例,改 Singleton 安全。② AddAIServices 现在直接注册 IEmbeddingService(Scoped,复用 Healnet:AI 的 Endpoint/ApiKey,经 IHttpClientFactory 复用连接池):此前只在 AddMemoryServices 内注册,仅需向量化能力的项目必须知道还要另调 AddMemoryServices 才能解析——隐蔽接入门槛已消除;工厂逻辑收敛到共享 CreateEmbeddingService(MemoryOptions 未注册时回退默认模型 text-embedding-v3),AddMemoryServices 路径行为不变(其内存配置仍优先生效)。③ 新增 4 项守卫测试(共 20 项):IAgentService 跨作用域同实例、运行时注册的 Agent 跨作用域存活(反射断言 _agents)、不调 AddMemoryServices 时 IEmbeddingService 可解析。QA 变异证伪:IAgentService 改回 AddScoped 被 2 项抓住。兼容性:DI 行为变化仅 IAgentService Singleton 化与 IEmbeddingService 新注册;AddMemoryServices 的既有消费方行为不变。依赖 Core 4.0.14。 v4.0.38: AI 服务生命周期缺陷修复(P0)+ DI 完整性守卫测试随批落地。① ICopilotClient 注册由 Scoped 改为 Singleton:IRAGService(Singleton,4.0.24 起)构造依赖它,两者组合自 4.0.24 起即非法——ValidateScopes/ValidateOnBuild(ASP.NET Core 在 Development 默认开启)下应用启动即抛 "Cannot consume scoped service 'ICopilotClient' from singleton 'IRAGService'"(生产不校验则单例隐式捕获一份永久化);且 CopilotClient/MicrosoftAIClient 是有状态实现(按 contextId 累积会话历史),Scoped 令每次请求丢历史、ClearContext 形同虚设。② 有状态单例必须有界:新增 ChatSessionStore<THistory>(会话数上限默认 1024、空闲 30 分钟淘汰、单会话消息数上限默认 100 裁剪最旧、同一 contextId 并发调用以会话门串行化);淘汰永不踢掉本次请求的会话(否则活跃但恰好最旧的会话会在自己的调用里历史归零);容量淘汰只在严格超过上限时触发(count == max 为合法满载)。③ 未配置 ApiKey 时降级注册 NullCopilotClient:容器图始终可解析、应用可正常启动,真正调用 AI 时才抛带配置指引的 InvalidOperationException(含 Healnet:AI:ApiKey 配置提示)——业务服务不再需要自行 GetService 判空 / try-catch 兜底(这正是每个新服务复制同一段防御代码的根因);其 ClearContext 为无副作用空操作。④ RabbitMQService(Singleton)的可变共享状态 _handlers/_declaredExchanges/_declaredQueues 由 Dictionary/List 改为 ConcurrentDictionary/ConcurrentBag(原无任何锁保护,并发订阅/声明存在竞态)。⑤ 新增 DiCompletenessTests 16 项守卫测试:ValidateOnBuild 全 provider 容器校验、NullCopilotClient 降级语义、根容器单例断言、跨调用历史保留 / ClearContext 生效 / 单会话裁剪 / 容量淘汰、同 contextId 并发串行化、RabbitMQ 并发容器反射断言。QA 变异证伪:改回 AddScoped 被 8 项抓住、移除 Null 兜底被 4 项抓住。兼容性:DI 行为变化仅 ICopilotClient Singleton 化与未配置降级;直接 new CopilotClient/MicrosoftAIClient 的使用方签名不变(新增可选参数)。依赖 Core 4.0.14。 v4.0.37: 开启 XML 注释文档生成 + 修净本包全部 XML 注释格式告警(只动注释与项目属性,IL 无变化)。① 此前本包不产 Healnet.Infrastructure.xml,包消费方引用 SwaggerOptions / GrpcChannelCache / AddHealnetInfrastructure / IMilvusService 等公开类型时【没有任何 IntelliSense 注释】;现启用 GenerateDocumentationFile,随包提供 lib/net10.0/Healnet.Infrastructure.xml(实测 974 个 member 条目),服务端模板的 XML 复制 Target 会一并带上(Swagger 里 gRPC/Consul/SqlSugar 等类型也有了描述)。② 修净 12 条 CS1570(未转义泛型尖括号)、7 条 CS1573(param 缺项:AddHealnetHealthChecks 两个重载的 milvusEnabled、IMilvusService 四个方法的 cancellationToken、MilvusField.FloatVector 的 description)、2 条 CS1587、1 条 CS0419(IEntityMapper 的 cref 指向 AddSqlSugar 重载不明确,改为带完整签名的 cref)。③ 一处结构性错位:私有常量 ConsulOperationTimeoutMs 的 summary 被夹在 AddConsulHttpClient 的 example/code 块内部,使 example 永不闭合、</example> 落到另一个私有方法之后(连带 2 条 CS1570)——已把该文档块移回 AddConsulHttpClient 上方;SqlSugarExtensions 把 summary 写在 ConfigureExternalServices 的 lambda 赋值上(非合法文档目标),改为普通注释。④ NoWarn 只保留 1591(公开面较大,补全缺注释不在本批范围);其余 XML 注释类告警不再抑制,将来格式错误会重新告警而非静默丢文档。依赖 Core 4.0.14。 v4.0.36: Swagger 文档三项 P3 修复(只影响文档生成,运行时行为不变)。① 移除 c.AddSecurityRequirement 的「全局安全要求」:它让文档里每个操作都带 security,Swagger UI 给所有端点画锁图标——包括模板中完全匿名的 GET /api/products(读者会误以为必须带 token)。改由新增的 AuthorizeAwareSecurityOperationFilter 逐操作声明:方法或其 Controller 上存在 [Authorize](IAuthorizeData)且任意一处都没有 [AllowAnonymous](IAllowAnonymous,优先于 Authorize)时才写 security;判定来源取 ActionDescriptor.EndpointMetadata ∪ 反射(MethodInfo/ControllerTypeInfo,inherit: true),兼顾 MVC 与 Minimal API/手工描述符。② 新增 DefaultResponsesOperationFilter,为 Controller 端点补齐框架实际会返回的 400/401/403/404/500(Swashbuckle 默认只生成 200),错误体经 ISchemaGenerator 生成 $ref 指向非泛型 ApiResponse(避免悬空引用、兼容 CustomSchemaIds);已声明同名状态码的操作(手写 [ProducesResponseType])与 gRPC 转码端点(/api/grpc 前缀或 GrpcTag 分组,其错误响应已由 GrpcSwaggerDocumentFilter 声明)自动跳过。③ 两个过滤器各由 SwaggerOptions 开关控制:DeclareAuthOnEndpoints / DeclareDefaultResponses(默认 true;置 false 可回退到「全局 security」/「只声明 200」的旧行为),并已在这两处配置绑定路径(AddSwagger(IConfiguration)、AddSwaggerWithGrpcSupport(configuration, ...))一并透传,避免配置里关开关静默失效。依赖 Core 4.0.13(ApiResponse 语义注释 + XML 文档生成,schema description 才有内容)。 ④ QA 复验修复:GetXmlCommentPaths 原把输出目录【所有】*.xml 全喂给 IncludeXmlComments,模板开启 CopyDocumentationFilesFromPackages 后要解析 100+ 个三方包文档(109 个 / 46MB),swagger.json 首/次耗时 0.354s→1.012s、0.124s→1.196s;现只选 Healnet.*.xml(框架契约)+ 入口程序集同名 .xml(业务 DTO),实测回到 0.159s / 0.035s,且不影响显式配置的 XmlCommentPaths(仍优先)。 ⑤ 同批加固(主理人返工要求):① 显式配置 XmlCommentPaths 时【完全采用配置值】、不再叠加自动扫描(否则「想收窄范围」的意图会被自动扫描打破);② 输出目录扫描结果按进程 Lazy 缓存,避免 AddSwagger 多次调用重复扫盘;③ 被服务端模板改为用 GeneratePathProperty 从 NuGet 包目录定向复制 Healnet.Core.xml(模板输出目录 xml 从 109 个 / 46MB 降到 1 个 / 152KB)。 v4.0.35: 依赖升级至 Healnet.Core 4.0.12。核查发现 4.0.34 打包时依赖 Core 4.0.11,而 4.0.11 的线上包缺少 ExceptionHandlerMiddleware 的「响应已开始写出」保护(该修复晚于 4.0.11 打包时刻),只升本包会拿到不含修复的 Core;故 Core 补发 4.0.12、本包随之升 4.0.35 以保证依赖解析到修复版本。本包自身代码与 4.0.34 完全一致(模型校验统一响应等能力不变)。 v4.0.34: 模型校验统一响应(兼容性接管,默认关闭)。此前 [ApiController] 的模型校验失败返回 RFC7807 ProblemDetails(HTTP 400),而框架其余错误统一走 ApiResponse,同一个「字段必填」错误存在两套 body 形状,调用方要写两份解析逻辑。现提供可选统一:新增 AddHealnetUnifiedValidationResponse 扩展与 Healnet:Validation 配置节(UnifyResponse / HttpStatusCode / ErrorCode / Message / IncludeFieldErrors / ForceJsonContentType)。UnifyResponse=false(默认)时不注册任何 MVC 行为,老调用方零影响;置 true 后校验失败返回 ApiResponse(code=400、success=false、字段明细放 data,结构与 ProblemDetails.errors 同构,前端把 body.errors.Name 改成 body.data.Name 即可迁移)。HttpStatusCode 默认仍 400(既有「看到 400 走失败分支」的判断不用改),可配 200 完全对齐 ApiResponse「HTTP 恒 200、错误看 body.code」的惯例;ForceJsonContentType 默认 true,避免项目注册 XML formatter 后同一响应因 Accept 不同而形状漂移。另在模板文档中警示:不支持给 record 主构造参数加 [property: Required](ASP.NET Core 会抛 InvalidOperationException,导致该接口所有 POST 变 500)。另供 E2E 使用的 ServiceProcess 增加 extraEnv 参数(验证开关两态),withGrpc=false 时显式关闭 GrpcPort 避免撞本机端口。 v4.0.31: 代码审查修复 3 项。① SqlSugarRepository 多库默认连接名不一致(P1):构造已按「连接配置首个 ConfigId」绑定 Context,但 GetClient 及全部 CRUD 方法默认参数恒为字面量 Default——多库配置首连接名非 Default(如 Master)时所有增删改查走 GetConnectionScope(Default) 抛「未找到 ConfigId」。现统一在 GetClient 入口做别名映射(请求 Default 且真实默认名不同时改用真实名),方法签名保持兼容。② GetSingleAsync/GetFirstAsync 性能缺陷:原实现 ToListAsync() 后 SingleOrDefault/FirstOrDefault 会把整表拉进内存,改为下推 SQL 的 SingleAsync/FirstAsync。③ ExceptionHandlerMiddleware 响应已开始写出时(SSE/大文件下载中途失败)再设 ContentType/StatusCode 会抛 InvalidOperationException 导致中间件自身崩溃,补 response.HasStarted 保护。另修复 ServiceDefaults 的 Swagger 生产门禁缺失(文档声明生产默认不挂载但实现未校验 AllowNonDevelopment,与网关门禁对齐,非 Development 环境需显式开启才挂载)。 v4.0.30: 彻底重写 gRPC 注解路由解析为强类型实现并新增依赖 Google.Protobuf 3.27.2 与 Google.Api.CommonProtos 2.15.0。4.0.29 的基类链 Descriptor 查找修复仍不够:MethodDescriptor 根本没有名为 Options 的属性(旧反射链在此恒断),且 Extensions.ContainsField API 形状也不存在,导致 google.api.http 注解永远读不到。现改为强类型:ServiceDescriptor.Methods → MethodDescriptor.CustomOptions.TryGetMessage(72295728) 读取 Google.Api.HttpRule,按 PatternCase(Get/Post/Put/Delete/Patch/Custom)成对取路径与 HTTP 方法,消除全部脆弱反射。 v4.0.29: 修复 gRPC 转码端点 Swagger 文档路由与真实路由不一致(P1,E2E 实测发现)。GetHttpRouteFromProtoDescriptor 的静态 Descriptor 查找只回溯实现类及其 DeclaringType,而 grpc-dotnet 生成结构中 Descriptor 位于基类链上某一层的 DeclaringType(实现类 UserGrpcService → 基类 UserGrpc.UserGrpcBase → 外层容器类 UserGrpc),导致 google.api.http 注解路由永远解析不到,Swagger 退化为合成回退路由(/grpc/{service}/{method},Try it out 必 404)。现沿整条基类链及其 DeclaringType 查找。另修复模板 ProductsController 实例字段保存跨请求状态缺陷(Controller 每请求新建,Create 后 Get 必 404),改为 Singleton InMemoryProductStore 注入。 v4.0.28: 修复 gRPC 服务类型识别规则在 grpc-dotnet 生成结构下恒不命中的缺陷(4.0.26 引入的自动探测/自动映射与 Swagger 自动发现均受影响)。此前 IsGrpcService 判定为'基类链上存在名以 Base 结尾且有 BindService 方法',但 grpc-dotnet 实际生成的结构是:服务实现类继承嵌套抽象类(如 UserGrpc.UserGrpcBase),BindService 定义在外层静态类(UserGrpc)上而非基类链上——导致自动探测 EnableGrpc 恒 false(ServiceDefaults 不启用 gRPC)、Swagger 自动发现也恒为空(此前未暴露是因为业务均显式传入服务类型)。现识别规则改为:基类链上存在名以 Base 结尾的类型,且该类型自身或其 DeclaringType(外层静态类)上存在 BindService 方法。ServiceDefaultsExtensions.IsGrpcServiceType 与 GrpcServiceScanner.IsGrpcService 同步修复。注意 BindService 在外层类上存在两个重载(BindService(base) / BindService(base, builder)),判定按方法名而非 GetMethod 精确签名(原写法触发 AmbiguousMatchException 启动崩溃)。 v4.0.27: 修复 4.0.26 Service Defaults 三处缺陷(发布后经三模板实机启动验证发现)。① MapAllDiscoveredGrpcServices 程序集排除规则误伤业务程序集:原笼统排除 FullName 以 Healnet 开头的程序集,导致 Healnet.Example.* 等业务服务的 gRPC 服务不被自动映射(转码端点 404);现改为精确排除 Healnet.Common/Healnet.Core/Healnet.Infrastructure 三个框架程序集(并补 mscorlib/netstandard)。② UseHealnetServiceDefaults 与 AddHealnetServiceDefaults 能力开关脱节:原 Use 侧从 Healnet:ServiceDefaults 配置新建 options(默认全 false),Add 侧的自动探测结果丢失,导致 Controller 端点不映射;现 Add 侧将探测后的 options 写入 DI(AddSingleton),Use 侧优先取 DI 实例,配置节点仍可覆盖。③ Kestrel 双端口策略修正并显式告警:明文端口的 Http1AndHttp2 无 TLS 时 HTTP/2 被禁用(Kestrel 事件 Http2DisabledWithHttp1AndNoTls,连接退化为 HTTP/1.1),此前'HTTP 与 gRPC 同端口共存'的原生 gRPC 调用实际不可用;现明确——EnableGrpc 且 GrpcPort 配置为独立端口(异于 ServicePort)时双端口(HTTP: Http1AndHttp2 + gRPC: HTTP/2 Only,原生 gRPC 唯一通路);GrpcPort 缺失或与 ServicePort 相同则记 Error 提示补配置(JSON 转码 HTTP 面不受影响)。混合宿主模板已改为双端口(5000 HTTP + 5001 gRPC),Consul 注册 grpc-port Meta 指向 5001,发现/通信全链路正确。 v4.0.26: 新增服务托管默认值 Service Defaults(HealnetServiceDefaultsExtensions),框架样板全收编,业务服务 Program.cs 只需两行调用。① AddHealnetServiceDefaults(WebApplicationBuilder):自动完成 Serilog 日志(UseHealnetSerilog)、Consul 客户端、gRPC JSON 转码 + 统一异常拦截器(按需)、MVC(按需)、JWT、健康检查、Swagger(含 gRPC 文档,服务类型自动发现)、Kestrel 端口策略(读 Healnet:Consul:ServicePort/GrpcPort——GrpcPort 大于 0 且异于 ServicePort 时双端口(HTTP: Http1AndHttp2 + gRPC: HTTP/2 Only),否则单端口 Http1AndHttp2(HTTP 与 gRPC 同端口共存,content-type 协商));能力开关默认自动探测入口程序集(存在 Controller 则启用 MVC、存在 gRPC 服务类则启用 gRPC),可经 HealnetServiceDefaultsOptions 委托显式覆盖。② UseHealnetServiceDefaults(WebApplication):按生产顺序挂载请求日志(/health 降噪)、全局异常(ExceptionHandlerMiddleware)、CorrelationId、认证授权、/health、MapControllers(按需)、自动发现并映射 gRPC 服务(MapAllDiscoveredGrpcServices,扫描非系统程序集中基类链含 BindService 的类型,逐个反射调用 MapGrpcService,业务无需手写 MapGrpcService)、Swagger UI、Consul 注册(Enabled 开关跳过)。③ 业务服务最终形态:builder.AddHealnetServiceDefaults() + app.UseHealnetServiceDefaults() + Run,业务代码只写 proto/gRPC 实现/Controller。④ 注意事项:混合宿主(HTTP 与 gRPC 同端口)必须将 Healnet:Consul:GrpcPort 配为与 ServicePort 相同值,Consul 注册才会写入 grpc-port Meta,其他服务的 gRPC 服务发现才能命中(发现侧跳过无 grpc-port 的实例,4.0.13 同样约束);自动映射 gRPC 服务后不要再手动调用 MapGrpcService&lt;T&gt;(同类型重复映射会抛端点重复异常)。模板案例见 examples/(MixedHost 混合宿主 / GrpcOnly 纯 gRPC 双端口 / ApiOnly 纯 HTTP) v4.0.25: gRPC 统一封装(业务服务开箱即得,无需自行注册)。① 服务端:AddGrpcJsonTranscodingSupport 现已默认注册 HealnetGrpcExceptionInterceptor(此前该拦截器为孤儿封装、全库无注册点,业务代码在 gRPC 服务中抛 HealnetException/BusinessException 会落入 Unknown/500);现自动转换异常为 gRPC Status(trailers 携带 x-error-code/x-error-retryable),JSON Transcoding 端点的 HTTP 状态码随之正确映射(NotFound→404、InvalidArgument→400、FailedPrecondition→400、PermissionDenied→403、ResourceExhausted→429、DeadlineExceeded→504、Unauthenticated→401),业务服务在 gRPC 方法中直接抛 Core 异常体系即可。② 客户端:GrpcClientBase 新增统一调用入口 ExecuteAsync——自动构建调用 metadata(x-correlation-id 链路透传,取自当前 Activity.TraceId;ForwardAuthorization=true 时透传调用方 Authorization header 到下游 gRPC metadata,供内部接口鉴权);并把 RpcException 还原为 HealnetException(服务端为 Healnet 框架时按 trailers x-error-code 精确还原原始错误码,否则按 StatusCode 退化映射:InvalidArgument→400、PermissionDenied→403、NotFound→404、ResourceExhausted→429、Internal→500、DeadlineExceeded→504、FailedPrecondition→400、Unauthenticated→401、Unavailable→503 可重试、Unimplemented→501、Aborted→409),消费方用统一 HTTP 语义错误码处理远程失败,不再感知 gRPC StatusCode/trailers 细节。新增 GrpcExceptionMapper(还原映射器)。③ 兼容性:GrpcClientBase 构造函数新增可选参数 IHttpContextAccessor(默认 null),既有子类无需改动;ExecuteAsync 为新增方法,原 GetClientAsync/GetRequiredClientAsync 用法不变;行为变化仅一处——此前 gRPC 服务中抛 Core 异常返回 Unknown 的场景现在返回精确 Status,属缺陷修复。 v4.0.24: 代码审查缺陷批量修复(正确性/安全/资源管理)。① GrpcChannelCache:健康检查失败的坏 Channel 先从缓存移除再重建(原 GetOrCreate 对已存在 key 直接返回旧坏实例,坏 Channel 永不重建);凭据按 URL scheme 选择(https→SecureSsl,原硬编码 Insecure 导致 https 目标握手失败)。② RabbitMQProducerBase:BasicPublishBatch/BasicPublish 发布操作加锁串行化(共享单例 channel 非线程安全,对照 RabbitMQService._publishLock 模式)。③ RabbitMQConsumerBase:重试耗尽与反序列化失败路径改为 DLQ 发布成功才 Ack,否则 BasicNack(requeue:false) 交给 broker 端 DLX 策略(原 DLQ 未启用或发布失败时无条件 Ack 静默丢消息)。④ DistributedLockService:锁值字典改 TryAdd 语义(原索引器赋值覆盖同键旧 token);释放时本地无 token 不再 KeyDelete 兜底(防误删其他实例持有的锁),仅告警,键由过期时间或真正持有者释放。⑤ MemoryOrchestrator:L2 持久化失败(保存失败或锁未获取)置 l2Persisted=false 如实返回(原静默吞掉仍返回 true);TurnNo 改 COUNT 聚合查询(原 GetRecentTurnsAsync(sessionId, 100000) 拉 10 万条仅为计数);Milvus FilterExpression 的 domain 加白名单校验(字母数字下划线中划线,不合法抛 ArgumentException,防表达式注入)。⑥ ConversationRepository:SaveSessionAsync/SaveTurnAsync 失败返回 false(配合 Core 4.0.11 的 IConversationRepository 契约),新增 CountTurnsAsync。⑦ RAGService 注册改 AddSingleton(其内部知识库字典随实例持久,Scoped 导致每个请求拿到空知识库)。⑧ AgentContextManager 加 TTL 惰性清理(1 小时,Get/Create/Exists/Count 路径触发,原只增不减内存泄漏);AgentService.ExecuteAsync/ExecuteWithToolsAsync 成功完成后调用 DeleteContextAsync。⑨ HttpClientService 全部方法(POST/PUT/DELETE/PATCH/表单 POST/下载字符串与字节数组/带状态码变体)统一经 BuildRequestUrlAsync 走 Consul 服务发现(原仅 GET 走,Consul 模式下其余方法相对路径请求必然失败)。⑩ AiMemoryEntityMapper:补 ConversationArchive.Id 列 IsPrimarykey/IsIdentity 映射(原空分支,CodeFirst 建表缺主键)。⑪ SqlSugarRepository:默认连接名取连接配置中的首个 ConfigId(原硬编码 "Default",多库首连接名非 Default 时仓储绑错库),取不到回退 "Default"。⑫ SqlSugarExtensions.OnLogExecuting 不再拼接 SQL 参数值(防手机号/金额等敏感数据泄漏进日志),仅保留 SQL 文本 Debug。⑬ ResiliencePolicyProvider 重试策略补 TaskCanceledException 覆盖(HttpClient 超时表现为该异常,原不重试),并排除外部取消(CancellationToken 已触发时不重试)。⑭ RabbitMQService 消费者由 EventingBasicConsumer(async void 事件,异常崩进程)改 AsyncEventingBasicConsumer;失败路径由 Nack(requeue:true) 改为 republish 带 x-retry-count=原值+1 header 的新消息并 Ack 原消息(原实现只读不写计数,Nack 重回队列 header 不变,毒消息无限循环),超过 MaxRetryCount(默认 3,新公开属性)转 BasicNack(requeue:false) 交 broker 端 DLX;Subscribe(queue, routingKey, handler) 重载标记 Obsolete(该重载错误地将 routingKey 用作 exchange 名称),5.0 移除。⑮ RedisService.GetAsync 区分 JsonException(Warning 日志,视为未命中)与连接类异常(Error 日志);仍返回 default,兼容性不变。⑯ ApiKeyAuthenticationHandler:API Key 比对由 string.Equals 改 CryptographicOperations.FixedTimeEquals 恒定时间比较(长度不等直接 false),防时序侧信道。⑰ ConsulService 实现 IDisposable 释放 ConsulClient(单例生命周期下原 HTTP 连接永不释放)。已知限制:全部契约接口补 CancellationToken 归 5.0;RedisShortTermMemoryStore 读改写改 Redis List 需数据迁移;MemoryOrchestrator 的 L3 蒸馏 fire-and-forget 需背景队列架构,另批处理。v4.0.23: 修复 Swagger gRPC 封装 4 处缺陷并增强 proto3 JSON 文档准确性(QA 团队双通道验证后实施)。① GetMethodType 流式识别失效:原实现对 Task`1 泛型定义名做 Contains 判断恒不命中,所有流式方法(ServerStreaming/ClientStreaming/DuplexStreaming)被误判为 Unary、x-grpc-type 恒为 Unary;现先解包 Task<T> 再与 Grpc.Core 的 AsyncServerStreamingCall<>/AsyncClientStreamingCall<,>/AsyncDuplexStreamingCall<,> 精确比较。② 流式假端点:GrpcSwaggerDocumentFilter 现跳过 ClientStreaming/DuplexStreaming(JSON Transcoding 官方不支持、经 HTTP 调用必然 404),并记 Information 日志;ServerStreaming 保留但在描述中标注响应为流式 JSON。③ int64 映射对齐 proto3 JSON:long/ulong 的 Schema 从 integer/int64 改为 string/int64、string/uint64(proto3 JSON 将 64 位整数编码为字符串,Transcoding 实际输出 "123");顺带补 uint→integer/int32(原落入默认 string 分支);MapField<long> 值同步修正。④ WellKnownTypes 盲区:Any 从空 object 改为带 @type 键提示与说明的开放对象(Any 打包类型为实例级信息,静态文档原理上无法展开,标注请按 @type 对应消息定义);Struct→任意 JSON 对象;Value→任意 JSON 值(不设 type);ListValue→任意值数组;FieldMask→逗号分隔字段路径字符串;NullValue→NULL_VALUE 枚举;Empty→空对象。⑤ 深度截断显式标注:嵌套超过 10 层降级为字符串时,Schema description 注明「[嵌套截断]」与被截断消息名,避免文档读者误读为真实字符串字段。⑥ 悬空 $ref:_currentDoc 为 null 时(如反射调用场景)CreateSchema 此前返回从未注册进 Components 的 Reference.Id,渲染解析失败;现改为返回已展开的内联 schema。⑦ ByteString Schema 补 format:byte,Swagger UI 可生成合法 base64 示例。⑧ 新增 gRPC 文件上传调试端点模板:MapGrpcFileUploadEndpoint(Swagger/GrpcFileUploadExtensions.cs)在 gRPC 服务同进程映射 multipart/form-data 上传端点(默认 /grpc-file-upload,可配置路由/大小上限/扩展名白名单/业务 Handler),返回统一 ApiResponse(code=200),Swagger UI 独立分组展示并支持文件选择框 Try it out——背景:JSON Transcoding 无 multipart,bytes 仅适合 base64 小内容,真实文件上传需传统 REST 端点。已冒烟实测:上传成功回显元信息/扩展名白名单拒绝 400/空请求 400/swagger.json 含 multipart requestBody 与独立分组。以上均已通过引用真实源码的验证 harness(伪 gRPC 服务 + 私有方法反射调用)回归实测。无公开 API 签名变更,行为向后兼容(文档描述更准确)。v4.0.22: 在 4.0.21 基础上补一处混合形状处理:当标量 MinimumLevel 与嵌套子节点同时存在时(例如环境变量 Healnet__Serilog__MinimumLevel=Error 叠加在 JSON 的嵌套对象之上),级别取标量,但嵌套里的 Override 仍然合并——此前只取标量会丢掉嵌套 Override。4.0.21/4.0.20 未公开该方法且无使用方,请直接用 4.0.22。v4.0.21: 修复 Healnet:Serilog 日志级别配置静默失效(4.0.20 为同一修复的中间发布,未公开解析方法且无使用方,请直接用 4.0.21)。LoggingOptions.MinimumLevel 是 string,而 Serilog.Settings.Configuration 的标准写法是嵌套对象 { "Default": .., "Override": { .. } };配置绑定遇到对象转 string 时会静默跳过该属性且不抛异常,最终 MinimumLevel 保持默认 "Information"、Override 为空字典——等价于"根本没配日志级别"。表现为:生产 Apollo 配 Warning 仍全量输出 Microsoft.AspNetCore 的 INF,本地配 Debug 却看不到任何 LogDebug。现新增公开的 LoggingExtensions.LoadLoggingOptions(IConfiguration) 显式兼容两种形状:标量形状直接采用;嵌套形状取 Default 并合并其 Override,同时通过 SelfLog 提示改回平级写法。Override 合并时平级(框架契约)优先于嵌套,同名键以平级为准,比较器改为 OrdinalIgnoreCase 以匹配 Serilog 的前缀匹配语义。公开该方法也便于服务在启动时直接打印"实际生效的日志配置"做诊断。无破坏性 API 变更,旧配置无需修改即可生效。v4.0.20: 同 4.0.21,中间发布。v4.0.19: IRedisService 新增 GetSubScriber() 方法,返回 StackExchange.Redis 的 ISubscriber,用于直接操作 Redis 发布/订阅(pub/sub)通道;RedisService 基于 _connection.GetSubscriber() 实现。注意:IRedisService 为公开接口,自行实现该接口的外部代码需补齐此方法。v4.0.16: 修复 YARP 服务发现"一缺全废"缺陷:Consul 中任一已配置服务无健康实例时,ConsulServiceDiscoveryConfigProvider.LoadConfigAsync 会在遍历中因 ConsulService.ResolveAllHttpAddressesAsync 抛 InvalidOperationException 而整体中断(异常被循环外层 catch 吞掉),导致此前已生成的路由全部丢弃、且每轮刷新均失败无法自愈——表现为"必须把所有下游服务全部启动,网关路由/Swagger 聚合才可用"。现按服务隔离异常:服务无实例(InvalidOperationException)仅记 Warning 并跳过该服务,其余服务路由照常生成(健康实例出现后 30s 内自动补齐);Consul 不可达等其他异常保留上一份配置,避免瞬时故障清空全部路由。无公开 API 签名变更,行为向后兼容。v4.0.13: gRPC 服务发现(ResolveAllGrpcAddressesAsync)支持遗留回退:实例无 grpc-port Meta 但 Tags 含 GrpcLegacyFallbackTag(默认 server,需 Healnet:Consul:GrpcLegacyTagFallback=true 开启)时,回退使用 Address:Port 作为 gRPC 地址,用于与历史 .NET Core 3.1 MicroCloud 框架注册的 gRPC 服务(不带 Meta、主端口即 h2c)互通;fail-fast 报错文案同步更新。默认关闭,行为完全向后兼容。:实例无 grpc-port Meta 但 Tags 含 GrpcLegacyFallbackTag(默认 server,需 Healnet:Consul:GrpcLegacyTagFallback=true 开启)时,回退使用 Address:Port 作为 gRPC 地址,用于与历史 .NET Core 3.1 MicroCloud 框架注册的 gRPC 服务(不带 Meta、主端口即 h2c)互通;fail-fast 报错文案同步更新。默认关闭,行为完全向后兼容。v4.0.12: 修复 RabbitMQ channel 泄漏导致连接触顶 ChannelAllocationException 的故障。此前 IRabbitMQService 注册为 Scoped,调用方用根 IServiceProvider.GetService 解析时每次新建 RabbitMQService 并在构造中 connection.CreateModel() 分配一个 channel;RabbitMQService 未实现 IDisposable 导致 scope 永不回收 channel,长时间运行后连接上 channel 只增不减,触顶 2047 上限即抛 ChannelAllocationException,进而拖垮依赖 MQ 的服务(如 identity 的 ValidateToken/AccountLogin/RefreshToken 空体 500)。现改为 AddSingleton(全进程复用 1 个 channel),RabbitMQService 实现 IDisposable(关闭时回收 channel),并对共享 channel 的发布/确认路径加锁以保证并发安全。无公开 API 签名变更,行为对既有调用方完全兼容(建议调用方仍用 GetService 懒获取而非构造硬注入)。v4.0.6: 三库版本重新对齐至统一 4.0.6(消除版本分叉,无新增代码变更/公开 API 变更,源码与 4.0.5 一致)。v4.0.2: GrpcChannelCache 创建的 HttpClient.Timeout 改为可配置(配置键 Grpc:HttpClientTimeoutSeconds,默认 100s 与 .NET 默认一致,保持既有行为)。此前 HttpClient 未显式设置 Timeout,恒为 100s 硬上限,且优先级高于 CallOptions.Deadline(grpc-dotnet 中 HttpClient.Timeout 先触发),导致调用方设置的更长 deadline(如编排层 DownstreamTimeoutSeconds=160,覆盖 LLM 生成 + 重试 >100s 的长查询)被 100s 硬截断,表现为客户端收到 "HttpClient.Timeout of 100 seconds elapsing" 的 Cancelled 状态。需要长超时的调用方现可在自身配置中调大该值(如 "gRPC": {"HttpClientTimeoutSeconds": 200})。无公开 API 签名变更,默认行为与 4.0.1 完全兼容。v4.0.1: 修复 AddMemoryServices 无条件注册 L4 归档服务的缺陷。此前 IArchiveRepository/IArchiveService 恒被注册,而 ArchiveService 硬依赖 IFileService,导致未注册文件存储的使用方即便 EnableArchive=false 也会在 DI 解析 MemoryOrchestrator 时抛 "Unable to resolve service for type 'IFileService' while attempting to activate 'ArchiveService'",只能在使用方 RemoveAll<IArchiveService>() 兜底。现改为仅当 MemoryOptions.EnableArchive 为 true 时才注册这两个服务,并在开启归档却缺失 IFileService 时抛出带注册指引的 InvalidOperationException。无公开 API 签名变更,行为对 EnableArchive=true 的使用方完全兼容。v4.0.0: 破坏性主版本(破坏性变更来自 Healnet.Core)。RedisService 实现 ICacheService.GetAndDeleteAsync<T>(Lua 原子 GET+DEL,防并发重复消费);OssFileService 剥离 endpoint 中重复的 bucket 子域前缀;LoggingExtensions 将 ES sink 由 Serilog.Sinks.Elasticsearch 切换为 Serilog.Sinks.OpenSearch 并启用 SelfLog 诊断(公开方法签名未变);AIServiceExtensions 调整 OpenAI HTTP 客户端超时逻辑。v3.1.0: OssFileService 实现 GeneratePresignedUrl(...) 预签名下载 URL(OSS 直连下载,配合 Healnet.Common 3.1.0 的 IFileService 扩展)。v3.0.1: ConsulService gRPC 发现改为 fail-fast 并支持唯一实例 ID 注册与 gRPC 健康检查;SqlSugarExtensions 注册 ITenant 多租户接口、AiMemoryEntityMapper DatabaseName 列标记可空;新增 GrpcClientBase 泛型基类;JwtBearer 跳过非 JWT 格式 Bearer token 避免 IDX14100 噪声、JWT bearer 对 /health 跳过校验;conversation_turn ErrorMessage 列映射标记 IsNullable。v3.0.0: 随 Healnet 统一升版至 3.0.0(破坏性变更来自 Healnet.Common:AESCrypto 移除无参重载、AESDecrypt 改返回元组)。v2.0.7: SqlSugar EntityMapper 可插拔化(IEntityMapper 接口)/ BusinessConfig + BusinessExample 迁出至业务项目 / ConversationArchive 泛化 / EntityService PropertyInfo 类型比较 bug 修复。v2.0.6: 新增 Milvus 向量数据库封装(IMilvusService / MilvusService / MilvusOptions / MilvusExtensions / MilvusHealthCheck),支持集合管理、向量索引、近似检索(ANN)、标量查询、批量写入与健康检查。v2.0.3: 统一三库版本号;升级目标框架至 net10.0;更新所有依赖包至最新稳定版;移除 Infrastructure 项目中多余的 MSBuild 属性。v2.0.1: 依赖包版本升级,修复若干已知问题。v2.0.0: 重大版本更新,目标框架从 net8.0 升级至 net10.0,全面更新依赖包版本,优化 API 设计。