如何在使用NSwag生成ASP.NET服务控制器时管理OpenAPI规范中的重复共享Schema声明
如何在使用NSwag生成ASP.NET服务控制器时管理OpenAPI规范中的重复共享Schema声明
我太懂你现在的困扰了——多个API服务共用一批基础Schema(比如错误响应、日期类型这些),但每次用NSwag生成控制器基类时,每个服务都会重复生成这些公共模型,不仅代码冗余到爆炸,后续改个公共字段都要在N个服务里同步,简直是维护噩梦。结合你给出的目录结构和已经踩过的坑,我整理了几个落地性强的解决方案,帮你彻底搞定这个问题:
方案一:单独生成公共Schema类库,服务级生成时复用(最推荐,一劳永逸)
这是从根源解决问题的方法:先把所有公共Schema单独生成一个共享类库,然后让每个服务的NSwag生成命令直接复用这个类库的类型,不再重复生成。
具体步骤:
- 包装公共Schema为完整的OpenAPI文档
NSwag的类生成命令需要处理合法的OpenAPI 3.x文档(必须包含openapi版本号),你之前直接用common/components/schemas下的零散文件或者不完整的YAML,NSwag根本不认。所以先创建一个完整的公共API文档,比如common-api.yml,内容如下:
openapi: 3.0.3 components: schemas: # 逐个引用你的公共Schema文件,或者用通配符(如果工具支持的话) CommonErrorResponse: $ref: './common/components/schemas/CommonErrorResponse.yml' DateTimeUtc: $ref: './common/components/schemas/DateTimeUtc.yml' PageMetadata: $ref: './common/components/schemas/PageMetadata.yml'
- 生成公共模型类库
用NSwag的openapi2csclass命令(专门用来生成数据模型类,不是控制器或客户端)来生成公共模型:
nswag openapi2csclass /input:common-api.yml /output:./Shared/Models/CommonModels.g.cs /namespace:YourSolution.Shared.Models /useNullableReferenceTypes:true
把生成的文件放到一个单独的类库项目(比如YourSolution.Shared)里,编译成DLL,让所有服务项目都引用这个类库。
- 调整服务控制器生成命令,复用公共类
在生成每个服务的控制器基类时,添加参数让NSwag加载公共类库,自动复用已有的公共类型,不再重复生成。修改后的命令示例:
nswag openapi2cscontroller /input:[你的服务打包后的OpenAPI文件路径] /output:./Controllers/[ServiceName]ControllerBase.g.cs /namespace:[你的控制器命名空间] /className:[ServiceName]ControllerBase /controllerStyle:abstract /useActionResultType:true /assemblyPaths:./Shared/bin/Debug/net8.0/YourSolution.Shared.dll /importTypes:YourSolution.Shared.Models
这里的关键参数:
/assemblyPaths:指定公共类库的编译后DLL路径,让NSwag能识别已存在的类型/importTypes:告诉NSwag优先使用这个命名空间下的已有类型,而不是重新生成
方案二:用NSwag配置文件统一管理排除的公共类型(临时过渡方案)
如果暂时不想折腾共享类库,可以用NSwag的配置文件统一管理需要排除的公共类型,避免在每个服务的命令行里写一大串/ExcludedTypeNames参数。
具体步骤:
- 创建NSwag配置文件
新建一个nswag-shared-config.json,把所有公共类型的名称都列在excludedTypeNames里:
{ "swaggerToCSharpController": { "controllerStyle": "Abstract", "useActionResultType": true, "excludedTypeNames": "CommonErrorResponse,DateTimeWithTimeZone,PagePaginationInfo", "namespace": "YourSolution.Services.[ServiceName].Controllers", "className": "[ServiceName]ControllerBase" } }
- 每个服务生成时引用这个配置
生成服务控制器时,用/config参数加载这个公共配置,再补充服务专属的参数:
nswag openapi2cscontroller /input:example-api.yml /output:./Controllers/ExampleAPIControllerBase.g.cs /config:nswag-shared-config.json /className:ExampleAPIControllerBase
后续新增公共类型时,只需要更新这个配置文件,不用修改每个服务的命令。不过这个方案只是“规避”重复生成,本质上还是需要维护排除列表,不如方案一彻底。
为什么你之前的尝试失败了?
- 之前直接用
common-schemas.yml(只有components/schemas)生成类失败:因为NSwag的类生成命令必须处理完整的OpenAPI文档(必须包含openapi:3.0.3这样的版本声明),零散的Schema片段它不处理。 - 之前把多个服务的生成文件放到同一个命名空间导致重复:因为你没有告诉NSwag这些类型已经存在,它会强制生成新的类,自然会出现重复定义的语法错误。
内容来源于stack exchange
相关产品推荐
相关产品推荐

