前言
在开发 RESTful API 时,良好的文档是必不可少的。Swagger 是一种广泛使用的 API 文档工具,可以资助我们生成交互式的 API 文档。然而,当项目规模增大,API 数目浩繁时,我们必要将 API 按照模块和版本进行分组,以便更好地管理和查找。本文将先容怎样在 .NET Core Web API 中使用 Swagger 按模块和版本分组,并使用自界说特性实现这一目的。
步骤一:安装 Swashbuckle.AspNetCore
首先,我们必要安装 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; }
- }
- }
复制代码 步骤三:配置 Swagger 生成文档
接下来,我们必要在 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。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |