在 C#/.NET Core 的 Web API 中使用 Swagger 按模块和版本分组并实现排序 ...

十念  论坛元老 | 2024-11-20 17:21:40 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1026|帖子 1026|积分 3078


前言

在开发 RESTful API 时,良好的文档是必不可少的。Swagger 是一种广泛使用的 API 文档工具,可以资助我们生成交互式的 API 文档。然而,当项目规模增大,API 数目浩繁时,我们必要将 API 按照模块和版本进行分组,以便更好地管理和查找。本文将先容怎样在 .NET Core Web API 中使用 Swagger 按模块和版本分组,并使用自界说特性实现这一目的。

步骤一:安装 Swashbuckle.AspNetCore

首先,我们必要安装 Swashbuckle.AspNetCore 包,这是 .NET Core 中用于集成 Swagger 的库。可以在项目的根目录下运行以下下令进行安装:
  1. dotnet add package Swashbuckle.AspNetCore
复制代码
步骤二:创建自界说特性

为了实现按模块和版本分组,我们必要创建一个自界说特性 ApiDescriptionAttribute。这个特性将用于标志我们的控制器,并包含模块名称、版本号和描述信息。
  1. using Microsoft.AspNetCore.Mvc.ApiExplorer;
  2. namespace WebApplication.ApiAttributes
  3. {
  4.     public class ApiDescriptionAttribute : Attribute, IApiDescriptionGroupNameProvider
  5.     {
  6.         public ApiDescriptionAttribute(string title, string? version = null, string? desc = null, int position = int.MaxValue)
  7.         {
  8.             GroupName = version != null ? $"{title}-{version}" : title;
  9.             Title = title;
  10.             Version = version;
  11.             Description = desc;
  12.             Position = position;
  13.         }
  14.         /// <summary>
  15.         /// 分组名称
  16.         /// </summary>
  17.         public string? GroupName { get; set; }
  18.         /// <summary>
  19.         /// Swagger 标题
  20.         /// </summary>
  21.         public string? Title { get; set; }
  22.         /// <summary>
  23.         /// 版本号
  24.         /// </summary>
  25.         public string? Version { get; set; }
  26.         /// <summary>
  27.         /// 描述
  28.         /// </summary>
  29.         public string? Description { get; set; }
  30.         /// <summary>
  31.         /// 分组顺序
  32.         /// </summary>
  33.         public int Position { get; set; }
  34.     }
  35. }
复制代码
步骤三:配置 Swagger 生成文档

接下来,我们必要在 Program.cs 中配置 Swagger,使其能够根据我们的自界说特性生成多个文档。
  1. public static void Main(string[] args)
  2. {
  3.     var builder = WebApplication.CreateBuilder(args);
  4.    
  5.     // 添加服务到容器
  6.     builder.Services.AddControllers();
  7.     builder.Services.AddEndpointsApiExplorer();
  8.     builder.Services.AddSwaggerGen(options =>
  9.     {
  10.         // 根据模块和版本生成多个文档
  11.         var apiAssembly = Assembly.GetExecutingAssembly();
  12.         var apiDescriptions = apiAssembly.GetTypes()
  13.             .Where(t => t.GetCustomAttributes<ApiDescriptionAttribute>().Any())
  14.             .Select(t => t.GetCustomAttribute<ApiDescriptionAttribute>())
  15.             .Distinct();
  16.         foreach (var desc in apiDescriptions)
  17.         {
  18.             if (desc != null)
  19.             {
  20.                 if (string.IsNullOrEmpty(desc.Version))
  21.                 {
  22.                     options.SwaggerDoc($"{desc.Title}", new OpenApiInfo { Title = $"{desc.Title} API", Version = desc.Version, Description = desc.Description, });
  23.                 }
  24.                 else
  25.                 {
  26.                     options.SwaggerDoc($"{desc.Title}-{desc.Version}", new OpenApiInfo
  27.                     {
  28.                         Title = $"{desc.Title} API",
  29.                         Version = desc.Version,
  30.                         Description = desc.Description,
  31.                     });
  32.                 }
  33.             }
  34.         }
  35.         //没有加特性的分到这个NoGroup上
  36.         options.SwaggerDoc("NoGroup", new OpenApiInfo
  37.         {
  38.             Title = "无分组"
  39.         });
  40.         //判断接口归于哪个分组
  41.         options.DocInclusionPredicate((docName, apiDescription) =>
  42.         {
  43.             if (docName == "NoGroup")
  44.             {
  45.                 //当分组为NoGroup时,只要没加特性的都属于这个组
  46.                 return string.IsNullOrEmpty(apiDescription.GroupName);
  47.             }
  48.             else
  49.             {
  50.                 return apiDescription.GroupName == docName;
  51.             }
  52.         });
  53.     });
  54.     var app = builder.Build();
  55.     // 配置 HTTP 请求管道
  56.     if (app.Environment.IsDevelopment())
  57.     {
  58.         app.UseSwagger();
  59.         app.UseSwaggerUI(options =>
  60.         {
  61.             // 根据模块和版本生成多个文档
  62.             var apiAssembly = Assembly.GetExecutingAssembly();
  63.             var apiDescriptions = apiAssembly.GetTypes()
  64.                 .Where(t => t.GetCustomAttributes<ApiDescriptionAttribute>().Any())
  65.                 .Select(t => t.GetCustomAttribute<ApiDescriptionAttribute>())
  66.                 .OrderBy(t => t?.Position ?? int.MaxValue).ThenBy(t => t?.Title).ThenBy(t => t?.Version)
  67.                 .Distinct();
  68.             foreach (var desc in apiDescriptions)
  69.             {
  70.                 if (desc != null)
  71.                 {
  72.                     if (string.IsNullOrEmpty(desc.Version))
  73.                     {
  74.                         options.SwaggerEndpoint($"/swagger/{desc.Title}/swagger.json", $"{desc.Title} API");
  75.                     }
  76.                     else
  77.                     {
  78.                         options.SwaggerEndpoint($"/swagger/{desc.Title}-{desc.Version}/swagger.json", $"{desc.Title} API {desc.Version}");
  79.                     }
  80.                 }
  81.             }
  82.             options.SwaggerEndpoint("/swagger/NoGroup/swagger.json", "无分组");
  83.         });
  84.     }
  85.     app.UseHttpsRedirection();
  86.     app.UseAuthorization();
  87.     app.MapControllers();
  88.     app.Run();
  89. }
复制代码
步骤四:标志控制器和方法

使用我们创建的 ApiDescriptionAttribute 来标志控制器和方法。以下是一些示例:
  1. using Microsoft.AspNetCore.Mvc;
  2. using WebApplication.ApiAttributes;
  3. namespace WebApplication.Controllers
  4. {
  5.     [ApiDescription("ModuleA", "v1", "A模组测试")]
  6.     [Route("api/[controller]")]
  7.     [ApiController]
  8.     public class ModuleA1Controller : ControllerBase
  9.     {
  10.         [HttpGet]
  11.         public IActionResult Get()
  12.         {
  13.             return Ok("Module A, Version 1");
  14.         }
  15.     }
  16. }
复制代码
  1. namespace WebApplication.Controllers
  2. {
  3.     [ApiDescription("ModuleA", "v2")]
  4.     [Route("api/[controller]")]
  5.     [ApiController]
  6.     public class ModuleA2Controller : ControllerBase
  7.     {
  8.         [HttpGet]
  9.         public IActionResult Get()
  10.         {
  11.             return Ok("Module A, Version 2");
  12.         }
  13.     }
  14. }
复制代码
  1. namespace WebApplication.Controllers
  2. {
  3.     [ApiDescription("ModuleB")]
  4.     [Route("api/[controller]")]
  5.     [ApiController]
  6.     public class ModuleBController : ControllerBase
  7.     {
  8.         [HttpGet]
  9.         public IActionResult Get()
  10.         {
  11.             return Ok("Module B, 仅有Title");
  12.         }
  13.     }
  14. }
复制代码
  1. namespace WebApplication.Controllers
  2. {
  3.     [ApiDescription("ModuleC")]
  4.     [Route("api/[controller]")]
  5.     [ApiController]
  6.     public class ModuleC1Controller : ControllerBase
  7.     {
  8.         [HttpGet]
  9.         public IActionResult Get()
  10.         {
  11.             return Ok("Module C1, 多Controller共用分组");
  12.         }
  13.     }
  14. }
复制代码
  1. namespace WebApplication.Controllers
  2. {
  3.     [ApiDescription("ModuleC")]
  4.     [Route("api/[controller]")]
  5.     [ApiController]
  6.     public class ModuleC2Controller : ControllerBase
  7.     {
  8.         [HttpGet]
  9.         public IActionResult Get()
  10.         {
  11.             return Ok("Module C2, 多Controller共用分组");
  12.         }
  13.     }
  14. }
复制代码
  1. namespace WebApplication.Controllers
  2. {
  3.     [ApiDescription("ModuleD", desc: "D模组测试")]
  4.     [Route("api/[controller]")]
  5.     [ApiController]
  6.     public class ModuleDController : ControllerBase
  7.     {
  8.         [HttpGet]
  9.         public IActionResult Get()
  10.         {
  11.             return Ok("Module D, 指定参数设置");
  12.         }
  13.     }
  14. }
复制代码
  1. namespace WebApplication.Controllers
  2. {
  3.     [Route("api/[controller]")]
  4.     [ApiController]
  5.     public class ModuleNoGroupController : ControllerBase
  6.     {
  7.         [HttpGet]
  8.         public IActionResult Get()
  9.         {
  10.             return Ok("Module NoGroup");
  11.         }
  12.     }
  13. }
复制代码
  1. namespace WebApplication.Controllers
  2. {
  3.     [ApiDescription("Position A", desc: "指定顺序", position: 1)]
  4.     [Route("api/[controller]")]
  5.     [ApiController]
  6.     public class PositionAController : ControllerBase
  7.     {
  8.         [HttpGet]
  9.         public IActionResult Get()
  10.         {
  11.             return Ok("Position A, 指定Swagger分组顺序");
  12.         }
  13.     }
  14. }
复制代码
  1. namespace WebApplication.Controllers
  2. {
  3.     [ApiDescription("Position Z", desc: "指定顺序", position: 0)]
  4.     [Route("api/[controller]")]
  5.     [ApiController]
  6.     public class PositionZController : ControllerBase
  7.     {
  8.         [HttpGet]
  9.         public IActionResult Get()
  10.         {
  11.             return Ok("Position Z, 指定Swagger分组顺序");
  12.         }
  13.     }
  14. }
复制代码
  1. namespace WebApplication.Controllers
  2. {
  3.     [Route("[controller]")]
  4.     [ApiDescription("天气", "v1", "天气预报")]
  5.     public class WeatherForecastController : ControllerBase
  6.     {
  7.         private static readonly string[] Summaries = new[]
  8.         {
  9.             "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
  10.         };
  11.         private readonly ILogger<WeatherForecastController> _logger;
  12.         public WeatherForecastController(ILogger<WeatherForecastController> logger)
  13.         {
  14.             _logger = logger;
  15.         }
  16.         [HttpGet(Name = "GetWeatherForecast")]
  17.         public IEnumerable<WeatherForecast> Get()
  18.         {
  19.             return Enumerable.Range(1, 5).Select(index => new WeatherForecast
  20.             {
  21.                 Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
  22.                 TemperatureC = Random.Shared.Next(-20, 55),
  23.                 Summary = Summaries[Random.Shared.Next(Summaries.Length)]
  24.             })
  25.             .ToArray();
  26.         }
  27.     }
  28. }
复制代码


总结

通过以上步骤,我们可以在 .NET Core Web API 项目中使用 Swagger 按模块和版本分组。这种实现方法使用了自界说特性来标志控制器,并在 Program.cs 中配置了 Swagger 以生成多个文档。如许,在 Swagger UI 中,我们可以根据模块和版本分别检察 API 文档,从而更好地管理和查找 API。这种方法不但提拔了文档的可读性,也增强了项目的可维护性,使开发者和使用者能更方便地交互与明白 API。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

十念

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表