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

CSDN 2024-08-27 12:03:01 阅读 55

文章目录

前言步骤一:安装 Swashbuckle.AspNetCore步骤二:创建自定义特性步骤三:配置 Swagger 生成文档步骤四:标记控制器和方法总结


前言

在开发 RESTful API 时,良好的文档是必不可少的。Swagger 是一种广泛使用的 API 文档工具,可以帮助我们生成交互式的 API 文档。然而,当项目规模增大,API 数量众多时,我们需要将 API 按照模块和版本进行分组,以便更好地管理和查找。本文将介绍如何在 .NET Core Web API 中使用 Swagger 按模块和版本分组,并使用自定义特性实现这一目标。


步骤一:安装 Swashbuckle.AspNetCore

首先,我们需要安装 Swashbuckle.AspNetCore 包,这是 .NET Core 中用于集成 Swagger 的库。可以在项目的根目录下运行以下命令进行安装:

<code>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();

}

}

}

Swagger截图


总结

通过以上步骤,我们可以在 .NET Core Web API 项目中使用 Swagger 按模块和版本分组。这种实现方法使用了自定义特性来标记控制器,并在 <code>Program.cs 中配置了 Swagger 以生成多个文档。这样,在 Swagger UI 中,我们可以根据模块和版本分别查看 API 文档,从而更好地管理和查找 API。这种方法不仅提升了文档的可读性,也增强了项目的可维护性,使开发者和使用者能更方便地交互与理解 API。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。