NSwag生成OpenAPI规范时CI/CD环境下未知API版本的处理方案问询
Great question! When working with NSwag in CI/CD pipelines where you don't know the exact document names (API versions) upfront, you don't need to add a dedicated endpoint to expose version info—there are cleaner, build-time-focused approaches to handle both scenarios you mentioned.
1. Generate Only the Default API Version's OAS Spec
If your API has a default version configured (either via the [ApiVersionNeutral] attribute on a controller, or by setting a default version in your API versioning setup), you can simplify your NSwag command by omitting the /documentName parameter entirely. NSwag will automatically pick up the default version's OpenAPI specification:
<Target Name="NSwag_GenerateDefault" AfterTargets="Build"> <Exec Command="$(NSwagExe_Core31) aspnetcore2openapi /project:$(AssemblyName).csproj /nobuild:true /output:OAS_Default.json" /> </Target>
If your default version has an explicit name (like v1), you can also define it as a reusable property in your .csproj or CI pipeline variables instead of hardcoding it—this keeps your build config flexible.
2. Generate OAS Specs for All Available Versions
To batch-generate specs for every version without hardcoding document names, you have two reliable options:
Option A: Use NSwag's Built-in listdocuments Command
NSwag includes a listdocuments subcommand that outputs all available document names for your project. You can capture this output in MSBuild and loop through each name to generate the corresponding spec:
<Target Name="NSwag_GenerateAllVersions" AfterTargets="Build"> <!-- Capture all document names from NSwag --> <Exec Command="$(NSwagExe_Core31) aspnetcore2openapi /project:$(AssemblyName).csproj /nobuild:true /listdocuments" ConsoleToMSBuild="true" EchoOff="true"> <Output TaskParameter="ConsoleOutput" PropertyName="AllDocumentNames" /> </Exec> <!-- Split the output into a clean list of document names --> <ItemGroup> <DocumentNames Include="$([System.String]::Split('$(AllDocumentNames)', '
'))" /> <DocumentNames Remove="" /> <!-- Filter out empty lines --> </ItemGroup> <!-- Generate a spec for each document name --> <Exec Command="$(NSwagExe_Core31) aspnetcore2openapi /project:$(AssemblyName).csproj /nobuild:true /documentName:%(DocumentNames.Identity) /output:OAS_%(DocumentNames.Identity).json" Condition="'%(DocumentNames.Identity)' != ''" /> </Target>
This target first runs listdocuments to fetch all version names, parses the output into an MSBuild item list, then executes NSwag for each version. The ConsoleToMSBuild="true" flag lets MSBuild capture the command's output directly.
Option B: Extract Versions Directly from Code
If you prefer not to rely on NSwag's list command, you can extract version strings directly from your controller code (assuming you use [ApiVersion] attributes). For example, in a CI pipeline using PowerShell:
# Scan all controller files for ApiVersion attributes and collect unique versions $apiVersions = Get-ChildItem -Path "./Controllers" -Filter "*.cs" | Select-String -Pattern '\[ApiVersion\("(.*?)"\)' | ForEach-Object { $_.Matches.Groups[1].Value } | Sort-Object -Unique # Generate an OAS spec for each version foreach ($version in $apiVersions) { & "$env:NSwagExe_Core31" aspnetcore2openapi /project:$(AssemblyName).csproj /nobuild:true /documentName:$version /output:"OAS_$version.json" }
This approach works well if your versioning is strictly tied to controller attributes, and avoids running NSwag twice (once to list, once to generate).
Both of these methods keep your service code clean (no extra endpoints) and handle the dynamic version scenario entirely at build/CI time.
内容的提问来源于stack exchange,提问作者JTIM

