C#/.NET 微服务架构:从入门到精通(五):配置Swagger文档+接口版本控制
前一篇我们完成了 EF Core + MySQL 的数据持久化落地,为微服务提供了数据层支撑。而在微服务开发中,接口文档管理与接口版本控制是提升协作效率、保证系统兼容性的关键 —— 微服务接口数量多、迭代快,清晰的文档能让前后端 / 跨团队协作更顺畅,版本控制则能避免接口升级对旧客户端的影响。
本篇将聚焦Swagger 文档配置与接口版本控制的实战集成,从基础搭建、扩展优化到多版本管理,手把手实现微服务接口的规范化管理。
一、微服务架构下的 Swagger 与接口版本控制
1. 为什么微服务需要 Swagger?
微服务由多个独立服务组成,每个服务暴露大量 API 接口,Swagger 的价值在于:
- 自动生成文档:无需手动维护接口文档,代码即文档;
- 在线调试接口:内置 UI 界面,直接测试接口请求 / 响应;
- 团队协作友好:前后端、跨服务团队通过统一文档对接,减少沟通成本;
- 支持认证集成:可配置 JWT/Token 等认证方式,直接测试需授权的接口。
2. 为什么微服务需要接口版本控制?
微服务接口迭代频繁(如新增字段、调整逻辑),版本控制能:
- 保证兼容性:旧版本客户端不受新版本接口影响;
- 支持并行迭代:多个版本接口可同时运行,平滑过渡;
- 规范接口管理:明确版本生命周期,避免接口混乱。
二、实战步骤 1:Swagger 文档基础配置
我们以商品Api(ProductApi) 为例,演示 Swagger 的完整配置。
1. 安装必需的 NuGet 包
在ProductApi项目中安装 Swashbuckle(.NET 官方推荐的 Swagger 工具):
dotnet add package Swashbuckle.AspNetCore --version 6.4.0

2. 基础配置:Program.cs 中注册 Swagger
修改Program.cs,在.NET 8 的顶级语句中,添加 Swagger 服务与中间件:
using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; using ProductApi.DbContexts; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); //注册Swagger生成器 builder.Services.AddSwaggerGen(c => { // 配置Swagger文档基本信息 c.SwaggerDoc("v1", new OpenApiInfo { Title = "商品 API", Version = "v1", Description = "基于.NET 8的微服务商品接口文档", Contact = new OpenApiContact { Name = "挺秃然的i", Url = new Uri("https://www.cnblogs.com/lantingxu") } }); }); //注册EF Core DbContext(连接MySQL) var connectionString = builder.Configuration.GetConnectionString("ProductDb"); builder.Services.AddDbContext<ProductDbContext>(options => { options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString), mysqlOpt => mysqlOpt.MigrationsAssembly(typeof(ProductDbContext).Assembly.FullName)); }); var app = builder.Build(); //配置Swagger中间件(仅在开发环境启用,生产环境可关闭) if (app.Environment.IsDevelopment()) { app.UseSwagger(); // 生成Swagger JSON端点(/swagger/v1/swagger.json) app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "商品 API v1"); c.RoutePrefix = "swagger"; // 将Swagger UI设为swagger路径(访问http://localhost:端口/swagger即可打开) }); } app.UseAuthorization(); app.MapControllers(); app.Run();
3. 验证 Swagger
运行ProductApi,访问http://localhost:你的端口/swagger,即可看到 Swagger UI 界面,显示所有 API 接口。

三、实战步骤 2:Swagger 扩展优化(XML 注释 + JWT 认证)
基础 Swagger 仅显示接口结构,我们需要添加XML 注释让文档更详细,以及JWT 认证配置支持测试需授权的接口。
1. 配置 XML 注释
步骤 1:启用项目 XML 文档生成
步骤 2:在 Swagger 中引入 XML 注释
修改AddSwaggerGen配置:
//注册Swagger生成器 builder.Services.AddSwaggerGen(c => { // 配置Swagger文档基本信息 c.SwaggerDoc("v1", new OpenApiInfo { Title = "商品 API", Version = "v1", Description = "基于.NET 8的微服务商品接口文档", Contact = new OpenApiContact { Name = "挺秃然的i", Url = new Uri("https://www.cnblogs.com/lantingxu") } }); // 引入控制器XML注释 var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath, true); // true表示包含控制器注释 });
步骤 3:给接口添加 XML 注释示例
在ProductController中添加注释:

步骤 4:验证Swagger
运行ProductApi,访问http://localhost:你的端口/swagger,即可看到 Swagger UI 界面,显示所有 API 接口。

2. 配置 JWT 认证支持(微服务常用)
如果微服务接口需要 JWT 授权,需在 Swagger 中添加 “小锁” 图标,支持输入 Token 测试,修改AddSwaggerGen配置:
//注册Swagger生成器 builder.Services.AddSwaggerGen(c => { // 配置Swagger文档基本信息 c.SwaggerDoc("v1", new OpenApiInfo { Title = "商品 API", Version = "v1", Description = "基于.NET 8的微服务商品接口文档", Contact = new OpenApiContact { Name = "挺秃然的i", Url = new Uri("https://www.cnblogs.com/lantingxu") } }); // 引入控制器XML注释 var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath, true); // true表示包含控制器注释 // 启用JWT授权 c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "请输入JWT Token(格式:Bearer {Token})", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, Scheme = "Bearer" }); // 全局应用JWT认证要求 c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); });
验证swagger

四、实战步骤 3:接口版本控制配置
微服务接口迭代时,需通过版本控制保证兼容性,我们使用微软官方最新的Asp.Versioning.Mvc包实现。
1. 安装必需的 NuGet 包
# API版本控制核心包 dotnet add package Asp.Versioning.Mvc --version 8.1.0 # 版本探索器 dotnet add package Asp.Versioning.Mvc.ApiExplorer --version 8.1.0

2. 配置版本控制服务
在Program.cs中注册版本控制:
/ 注册接口版本控制 builder.Services.AddApiVersioning(options => { options.DefaultApiVersion = new ApiVersion(1, 0); // 默认版本v1.0 options.AssumeDefaultVersionWhenUnspecified = true; // 未指定版本时使用默认版本 options.ReportApiVersions = true; // 在响应头中返回支持的版本 // 配置版本读取方式(支持多种方式,这里演示URL路径方式,最直观) options.ApiVersionReader = ApiVersionReader.Combine( new UrlSegmentApiVersionReader() // URL路径版本:/api/v1/User // 也可添加查询字符串方式:/api/User?api-version=1.0 // new QueryStringApiVersionReader("api-version"), // 或请求头方式:Header中添加Api-Version: 1.0 // new HeaderApiVersionReader("Api-Version") ); }) //注册版本探索器(与Swagger集成必需) .AddMvc() .AddApiExplorer(options => { options.GroupNameFormat = "'v'VVV"; // 版本组名格式:v1、v1.1 options.SubstituteApiVersionInUrl = true; // 替换URL中的版本占位符 });

3. 创建多版本控制器示例
调整一下Controllers文件夹,创建两个版本的产品控制器,演示版本隔离:
V1版本的ProductController:
using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using ProductApi.DbContexts; using ProductApi.Entities; namespace ProductApi.Controllers.V1; /// <summary> /// 商品控制器v1版本 /// </summary> [ApiVersion(1.0)] // 标记版本v1.0 [Route("api/v{version:apiVersion}/[controller]")] // URL路径包含版本 [ApiController] public class ProductController : ControllerBase { private readonly ProductDbContext _context; /// <summary> /// 构造函数 /// </summary> /// <param name="context"></param> public ProductController(ProductDbContext context) { _context = context; } /// <summary> /// 获取所有商品 /// </summary> /// <returns></returns> [HttpGet] public async Task<ActionResult<IEnumerable<Product>>> GetProducts() { // AsNoTracking:查询优化,不跟踪实体状态(微服务读多写少场景推荐) return await _context.Products.AsNoTracking().ToListAsync(); } /// <summary> /// 获取单个商品 /// </summary> /// <param name="id">主键Id</param> /// <returns></returns> [HttpGet("{id}")] public async Task<ActionResult<Product>> GetProduct(long id) { var product = await _context.Products.FindAsync(id); if (product == null) return NotFound(); return product; } }
V2版本的ProductController:
using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using ProductApi.DbContexts; using ProductApi.Entities; namespace ProductApi.Controllers.V2; /// <summary> /// 商品控制器v2版本 /// </summary> [ApiVersion(2.0)] // 标记版本v2.0 [Route("api/v{version:apiVersion}/[controller]")] [ApiController] public class ProductController : ControllerBase { private readonly ProductDbContext _context; /// <summary> /// 构造函数 /// </summary> /// <param name="context"></param> public ProductController(ProductDbContext context) { _context = context; } /// <summary> /// 获取所有商品 /// </summary> /// <returns></returns> [HttpGet] public async Task<ActionResult<IEnumerable<Product>>> GetProducts() { // AsNoTracking:查询优化,不跟踪实体状态(微服务读多写少场景推荐) return await _context.Products.AsNoTracking().ToListAsync(); } /// <summary> /// 获取单个商品 /// </summary> /// <param name="id">主键Id</param> /// <returns></returns> [HttpGet("{id}")] public async Task<ActionResult<Product>> GetProduct(long id) { var product = await _context.Products.FindAsync(id); if (product == null) return NotFound(); return product; } /// <summary> /// 新增商品 /// </summary> /// <param name="product">商品</param> /// <returns></returns> [HttpPost] public async Task<ActionResult<Product>> PostProduct(Product product) { _context.Products.Add(product); await _context.SaveChangesAsync(); return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product); } /// <summary> /// 更新商品 /// </summary> /// <param name="id">主键Id</param> /// <param name="product">商品</param> /// <returns></returns> [HttpPut("{id}")] public async Task<IActionResult> PutProduct(long id, Product product) { if (id != product.Id) return BadRequest(); _context.Entry(product).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!ProductExists(id)) return NotFound(); else throw; } return NoContent(); } /// <summary> /// 删除商品 /// </summary> /// <param name="id">主键Id</param> /// <returns></returns> [HttpDelete("{id}")] public async Task<IActionResult> DeleteProduct(long id) { var product = await _context.Products.FindAsync(id); if (product == null) return NotFound(); // 软删除:仅标记IsDeleted,不物理删除 product.IsDeleted = true; await _context.SaveChangesAsync(); return NoContent(); } private bool ProductExists(long id) { return _context.Products.Any(e => e.Id == id); } }
最终拆分:

五、实战步骤 4:Swagger 与多版本控制集成
让 Swagger 自动识别并显示不同版本的接口,修改 Swagger 配置:
1. 修改 Swagger 生成器配置
在Program.cs中,通过IApiVersionDescriptionProvider动态生成多版本 Swagger 文档:
// 动态获取所有版本信息,生成对应的SwaggerDoc using var scope = builder.Services.BuildServiceProvider().CreateScope(); var provider = scope.ServiceProvider.GetRequiredService<IApiVersionDescriptionProvider>(); foreach (var description in provider.ApiVersionDescriptions) { c.SwaggerDoc(description.GroupName, new OpenApiInfo { Title = $"商品 API {description.GroupName}", Version = description.GroupName, Description = description.IsDeprecated ? "该版本已废弃" : "当前稳定版本", Contact = new OpenApiContact { Name = "挺秃然的i", Url = new Uri("https://www.cnblogs.com/lantingxu") } }); }

2. 修改 Swagger UI 配置
让 Swagger UI 显示多版本切换下拉框:
//配置Swagger中间件(仅在开发环境启用,生产环境可关闭) if (app.Environment.IsDevelopment()) { app.UseSwagger(); // 生成Swagger JSON端点(/swagger/v1/swagger.json) app.UseSwaggerUI(c => { //c.SwaggerEndpoint("/swagger/v1/swagger.json", "商品 API v1"); // 动态获取所有版本,配置Swagger端点 var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>(); foreach (var description in provider.ApiVersionDescriptions) { c.SwaggerEndpoint( $"/swagger/{description.GroupName}/swagger.json", $"商品 API {description.GroupName}" ); } c.RoutePrefix = "swagger"; // 将Swagger UI设为swagger路径(访问http://localhost:端口/swagger即可打开) }); }

3. 验证多版本 Swagger
运行服务,访问 Swagger UI,右上角会出现版本下拉框,可切换 v1、v2 版本查看对应接口。


六、最佳实践
1. XML 注释规范
- 所有控制器、接口、参数、返回值必须添加注释;
- 复杂实体也需在属性上添加注释,Swagger 会自动显示在模型说明中
2. 接口版本管理
- 版本号规则:使用语义化版本(MAJOR.MINOR),如 v1、v1.1,仅在不兼容变更时升级 MAJOR 版本;
- 废弃策略:旧版本接口用
[ApiVersion(1.0, Deprecated = true)]标记,Swagger 会显示 “已废弃” 提示; - 过渡周期:保留旧版本至少 1-2 个迭代周期,给客户端足够时间升级。
3. 生产环境 Swagger 配置
- 限制访问:生产环境建议关闭 Swagger,或通过身份认证(如添加中间件验证请求头)限制仅内部网络访问;
- 环境隔离:通过
app.Environment.IsDevelopment()判断,仅在开发 / 测试环境启用 Swagger UI。
七、常见问题解决
1. XML 注释不显示
- 检查项目属性是否勾选 “XML 文档文件”;
- 确认
IncludeXmlComments的路径正确(使用AppContext.BaseDirectory获取运行时路径); - 实体类的 XML 注释需在
IncludeXmlComments中设置第二个参数为true。
2. Swagger 找不到多版本接口
- 检查控制器的
[ApiVersion]和[Route]特性是否正确(Route 中需包含v{version:apiVersion}); - 确认
AddApiExplorer的SubstituteApiVersionInUrl设为true; - 检查 Swagger 生成器中是否通过
IApiVersionDescriptionProvider动态配置了SwaggerDoc。
3. 版本控制冲突
- 避免同时使用多种版本读取方式(如 URL 路径 + 查询字符串),优先用 URL 路径方式(最直观);
- 确保所有控制器都标记了
[ApiVersion],未标记的会使用默认版本。
八、总结
本篇我们完成了Swagger 文档配置与接口版本控制的全流程集成:
- 搭建 Swagger 基础环境,实现接口文档自动生成与在线调试;
- 扩展 Swagger 配置,添加 XML 注释让文档更详细,集成 JWT 认证支持测试授权接口;
- 配置接口版本控制,通过 URL 路径方式实现多版本隔离;
- 实现 Swagger 与多版本控制的集成,支持在 UI 中切换查看不同版本的接口;
- 梳理了 XML 注释规范、版本管理策略、生产环境配置等最佳实践。

浙公网安备 33010602011771号