赞
踩
在开发 RESTful API 时,良好的文档是必不可少的。Swagger 是一种广泛使用的 API 文档工具,可以帮助我们生成交互式的 API 文档。然而,当项目规模增大,API 数量众多时,我们需要将 API 按照模块和版本进行分组,以便更好地管理和查找。本文将介绍如何在 .NET Core Web API 中使用 Swagger 按模块和版本分组,并使用自定义特性实现这一目标。
首先,我们需要安装 Swashbuckle.AspNetCore 包,这是 .NET Core 中用于集成 Swagger 的库。可以在项目的根目录下运行以下命令进行安装:
dotnet add package Swashbuckle.AspNetCore
为了实现按模块和版本分组,我们需要创建一个自定义特性 ApiDescriptionAttribute
。这个特性将用于标记我们的控制器,并包含模块名称、版本号和描述信息。
using Microsoft.AspNetCore.Mvc.ApiExplorer; namespace WebApplication.ApiAttributes { public class ApiDescriptionAttribute : Attribute, IApiDescriptionGroupNameProvider { public ApiDescriptionAttribute(string title, string? version = null, string? desc = null, int position = int.MaxValue) { GroupName = version != null ? $"{title}-{version}" : title; Title = title; Version = version; Description = desc; Position = position; } /// <summary> /// 分组名称 /// </summary> public string? GroupName { get; set; } /// <summary> /// Swagger 标题 /// </summary> public string? Title { get; set; } /// <summary> /// 版本号 /// </summary> public string? Version { get; set; } /// <summary> /// 描述 /// </summary> public string? Description { get; set; } /// <summary> /// 分组顺序 /// </summary> public int Position { get; set; } } }
接下来,我们需要在 Program.cs
中配置 Swagger,使其能够根据我们的自定义特性生成多个文档。
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // 添加服务到容器 builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { // 根据模块和版本生成多个文档 var apiAssembly = Assembly.GetExecutingAssembly(); var apiDescriptions = apiAssembly.GetTypes() .Where(t => t.GetCustomAttributes<ApiDescriptionAttribute>().Any()) .Select(t => t.GetCustomAttribute<ApiDescriptionAttribute>()) .Distinct(); foreach (var desc in apiDescriptions) { if (desc != null) { if (string.IsNullOrEmpty(desc.Version)) { options.SwaggerDoc($"{desc.Title}", new OpenApiInfo { Title = $"{desc.Title} API", Version = desc.Version, Description = desc.Description, }); } else { options.SwaggerDoc($"{desc.Title}-{desc.Version}", new OpenApiInfo { Title = $"{desc.Title} API", Version = desc.Version, Description = desc.Description, }); } } } //没有加特性的分到这个NoGroup上 options.SwaggerDoc("NoGroup", new OpenApiInfo { Title = "无分组" }); //判断接口归于哪个分组 options.DocInclusionPredicate((docName, apiDescription) => { if (docName == "NoGroup") { //当分组为NoGroup时,只要没加特性的都属于这个组 return string.IsNullOrEmpty(apiDescription.GroupName); } else { return apiDescription.GroupName == docName; } }); }); var app = builder.Build(); // 配置 HTTP 请求管道 if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(options => { // 根据模块和版本生成多个文档 var apiAssembly = Assembly.GetExecutingAssembly(); var apiDescriptions = apiAssembly.GetTypes() .Where(t => t.GetCustomAttributes<ApiDescriptionAttribute>().Any()) .Select(t => t.GetCustomAttribute<ApiDescriptionAttribute>()) .OrderBy(t => t?.Position ?? int.MaxValue).ThenBy(t => t?.Title).ThenBy(t => t?.Version) .Distinct(); foreach (var desc in apiDescriptions) { if (desc != null) { if (string.IsNullOrEmpty(desc.Version)) { options.SwaggerEndpoint($"/swagger/{desc.Title}/swagger.json", $"{desc.Title} API"); } else { options.SwaggerEndpoint($"/swagger/{desc.Title}-{desc.Version}/swagger.json", $"{desc.Title} API {desc.Version}"); } } } options.SwaggerEndpoint("/swagger/NoGroup/swagger.json", "无分组"); }); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); }
使用我们创建的 ApiDescriptionAttribute
来标记控制器和方法。以下是一些示例:
using Microsoft.AspNetCore.Mvc; using WebApplication.ApiAttributes; namespace WebApplication.Controllers { [ApiDescription("ModuleA", "v1", "A模组测试")] [Route("api/[controller]")] [ApiController] public class ModuleA1Controller : ControllerBase { [HttpGet] public IActionResult Get() { return Ok("Module A, Version 1"); } } }
namespace WebApplication.Controllers
{
[ApiDescription("ModuleA", "v2")]
[Route("api/[controller]")]
[ApiController]
public class ModuleA2Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Module A, Version 2");
}
}
}
namespace WebApplication.Controllers
{
[ApiDescription("ModuleB")]
[Route("api/[controller]")]
[ApiController]
public class ModuleBController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Module B, 仅有Title");
}
}
}
namespace WebApplication.Controllers
{
[ApiDescription("ModuleC")]
[Route("api/[controller]")]
[ApiController]
public class ModuleC1Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Module C1, 多Controller共用分组");
}
}
}
namespace WebApplication.Controllers
{
[ApiDescription("ModuleC")]
[Route("api/[controller]")]
[ApiController]
public class ModuleC2Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Module C2, 多Controller共用分组");
}
}
}
namespace WebApplication.Controllers
{
[ApiDescription("ModuleD", desc: "D模组测试")]
[Route("api/[controller]")]
[ApiController]
public class ModuleDController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Module D, 指定参数设置");
}
}
}
namespace WebApplication.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ModuleNoGroupController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Module NoGroup");
}
}
}
namespace WebApplication.Controllers
{
[ApiDescription("Position A", desc: "指定顺序", position: 1)]
[Route("api/[controller]")]
[ApiController]
public class PositionAController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Position A, 指定Swagger分组顺序");
}
}
}
namespace WebApplication.Controllers
{
[ApiDescription("Position Z", desc: "指定顺序", position: 0)]
[Route("api/[controller]")]
[ApiController]
public class PositionZController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok("Position Z, 指定Swagger分组顺序");
}
}
}
namespace WebApplication.Controllers { [Route("[controller]")] [ApiDescription("天气", "v1", "天气预报")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet(Name = "GetWeatherForecast")] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); } } }
通过以上步骤,我们可以在 .NET Core Web API 项目中使用 Swagger 按模块和版本分组。这种实现方法使用了自定义特性来标记控制器,并在 Program.cs
中配置了 Swagger 以生成多个文档。这样,在 Swagger UI 中,我们可以根据模块和版本分别查看 API 文档,从而更好地管理和查找 API。这种方法不仅提升了文档的可读性,也增强了项目的可维护性,使开发者和使用者能更方便地交互与理解 API。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。