You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET 5 REST API的Swagger中同时实现API版本控制与分组功能

.NET 5 WebAPI 同时实现版本控制+Swagger分组管理完整方案

1 前置依赖安装

先安装所需NuGet包:

  • Swashbuckle.AspNetCore:Swagger核心组件
  • Microsoft.AspNetCore.Mvc.Versioning:API版本控制组件
  • Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer:版本信息暴露组件,用于对接Swagger

2 自定义扩展类

2.1 接口业务分组特性

用于标记控制器/接口所属的业务分组

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class ApiGroupAttribute : Attribute
{
    /// <summary>
    /// 分组名称
    /// </summary>
    public string GroupName { get; }
    public ApiGroupAttribute(string groupName)
    {
        GroupName = groupName;
    }
}

2.2 Swagger文档过滤器

用于按「版本+业务分组」自动分配接口到对应文档

using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Microsoft.AspNetCore.Mvc.ApiExplorer;

public class SwaggerDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        var currentDocKey = swaggerDoc.Info.Title.Split('|')[0].Trim();
        // 过滤不属于当前文档的接口
        var invalidApis = context.ApiDescriptions
            .Where(apiDesc =>
            {
                var apiVersion = apiDesc.GetApiVersion().ToString();
                var groupAttr = apiDesc.ActionDescriptor.EndpointMetadata
                    .OfType<ApiGroupAttribute>()
                    .FirstOrDefault();
                var groupName = groupAttr?.GroupName ?? "Default";
                var apiKey = $"v{apiVersion}_{groupName}";
                return apiKey != currentDocKey;
            })
            .ToList();

        foreach (var api in invalidApis)
        {
            swaggerDoc.Paths.Remove($"/{api.RelativePath}");
        }
    }
}

3 Startup配置

3.1 ConfigureServices配置

using Microsoft.AspNetCore.Mvc;

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    // 配置API版本控制
    services.AddApiVersioning(opt =>
    {
        opt.DefaultApiVersion = new ApiVersion(1, 0);
        // 未指定版本时使用默认版本
        opt.AssumeDefaultVersionWhenUnspecified = true;
        // 返回响应头中支持的版本信息
        opt.ReportApiVersions = true;
    })
    .AddApiExplorer(opt =>
    {
        // 版本号格式:v1、v2
        opt.GroupNameFormat = "'v'VVV";
        // 自动替换路由中的版本占位符
        opt.SubstituteApiVersionInUrl = true;
    });

    // 配置Swagger
    services.AddSwaggerGen(opt =>
    {
        // 配置所有版本+分组的文档定义,新增版本/分组只需修改下方两个数组即可
        var versions = new[] { "v1", "v2" };
        var groups = new[] { "User", "Order", "Payment", "Default" };
        foreach (var version in versions)
        {
            foreach (var group in groups)
            {
                opt.SwaggerDoc($"{version}_{group}", new OpenApiInfo
                {
                    Title = $"{version}_{group} | 接口文档",
                    Version = version,
                    Description = $"{version}版本 {group}业务域接口集合"
                });
            }
        }

        // 应用自定义文档过滤器
        opt.DocumentFilter<SwaggerDocumentFilter>();

        // 可选:JWT授权配置,有认证需求可添加
        var securityScheme = new OpenApiSecurityScheme
        {
            Name = "Authorization",
            Type = SecuritySchemeType.ApiKey,
            Scheme = "Bearer",
            BearerFormat = "JWT",
            In = ParameterLocation.Header,
            Description = "JWT授权头格式:Bearer {Token}"
        };
        opt.AddSecurityDefinition("Bearer", securityScheme);
        opt.AddSecurityRequirement(new OpenApiSecurityRequirement
        {
            {
                new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
                },
                Array.Empty<string>()
            }
        });
    });
}

3.2 Configure中间件配置

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        // 启用Swagger中间件
        app.UseSwagger();
        app.UseSwaggerUI(opt =>
        {
            // 生成Swagger UI右上角的版本分组切换选项
            var versions = new[] { "v1", "v2" };
            var groups = new[] { "User", "Order", "Payment", "Default" };
            foreach (var version in versions)
            {
                foreach (var group in groups)
                {
                    opt.SwaggerEndpoint($"/swagger/{version}_{group}/swagger.json", $"{version} {group}接口");
                }
            }
            // Swagger访问路径前缀,设为空则根路径直接访问
            opt.RoutePrefix = "swagger";
        });
    }

    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

4 控制器使用示例

4.1 V1版本用户分组接口

[ApiController]
[Route("api/v{version:apiVersion}/user")]
[ApiVersion("1.0")]
[ApiGroup("User")]
public class UserV1Controller : ControllerBase
{
    [HttpGet("info")]
    public IActionResult GetUserInfo()
    {
        return Ok(new { UserId = 1, UserName = "张三", ApiVersion = "v1" });
    }
}

4.2 V2版本订单分组接口

[ApiController]
[Route("api/v{version:apiVersion}/order")]
[ApiVersion("2.0")]
[ApiGroup("Order")]
public class OrderV2Controller : ControllerBase
{
    [HttpGet("list")]
    public IActionResult GetOrderList()
    {
        return Ok(new { OrderIds = new[] { 1001, 1002, 1003 }, ApiVersion = "v2" });
    }
}

5 使用说明

  • 新增版本只需在Swagger配置的versions数组添加对应版本号即可
  • 新增业务分组只需在Swagger配置的groups数组添加对应分组名即可
  • 控制器/Action未添加[ApiGroup]特性时,默认归到Default分组
  • Action上的[ApiGroup]特性优先级高于控制器上的特性,可实现单个接口单独分组
  • 启动项目后访问/swagger即可在右上角切换不同版本、不同分组的接口文档

内容的提问来源于stack exchange,提问作者Matthew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 22:09:02