# 接口文档 (05_Swagger)

最后更新: 2024-09-20


# 📚 概述

DarkM Swagger 模块提供 API 接口文档生成功能,支持 API 分组、版本控制、自定义过滤器等功能。

源代码位置: DarkM/src/Framework/Swagger


# 🏗️ 模块架构

# 完整目录结构

Swagger/
└── Swagger.Core/
    ├── Filters/
    │   ├── LowercaseDocumentFilter.cs     # 小写文档过滤器
    │   ├── IgnorePropertySchemaFilter.cs  # 忽略属性过滤器
    │   ├── EnumSchemaFilter.cs            # 枚举过滤器
    │   └── DescriptionDocumentFilter.cs   # 描述文档过滤器
    ├── Conventions/
    │   └── ApiExplorerGroupPerVersionConvention.cs  # API 分组约定
    ├── Extensions/
    │   └── ModuleDescriptorExtensions.cs  # 模块描述符扩展
    ├── ServiceCollectionExtensions.cs     # 服务注册
    └── ApplicationBuilderExtensions.cs    # 应用构建
1
2
3
4
5
6
7
8
9
10
11
12
13

# 💡 配置说明

# appsettings.json 配置

{
  "Host": {
    // 是否启用 Swagger
    "Swagger": true
  }
}
1
2
3
4
5
6

说明: 开发模式下会自动启用,生产环境需手动开启。


# 🔧 核心功能

# 1. API 分组约定

文件位置: Swagger.Core/Conventions/ApiExplorerGroupPerVersionConvention.cs

public class ApiExplorerGroupPerVersionConvention : IControllerModelConvention
{
    public void Apply(ControllerModel controller)
    {
        var controllerVersion = controller.Selectors
            .FirstOrDefault()?
            .AttributeRouteModel?
            .Template?
            .Split('/')?
            .FirstOrDefault()?
            .Replace("v", "");

        if (int.TryParse(controllerVersion, out var version))
        {
            controller.GroupName = $"v{version}";
        }
        else
        {
            controller.GroupName = "v1";
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

功能: 自动根据 Controller 路由中的版本号进行分组。


# 2. 自定义过滤器

# LowercaseDocumentFilter(小写文档)

文件位置: Swagger.Core/Filters/LowercaseDocumentFilter.cs

public class LowercaseDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        var paths = new OpenApiPaths();

        foreach (var (key, value) in swaggerDoc.Paths)
        {
            paths.Add(key.ToLower(), value);
        }

        swaggerDoc.Paths = paths;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

功能: 将所有 API 路径转换为小写。


# IgnorePropertySchemaFilter(忽略属性过滤器)

文件位置: Swagger.Core/Filters/IgnorePropertySchemaFilter.cs

public class IgnorePropertySchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        // 忽略特定属性
        var propertiesToIgnore = new[] { "password", "secret" };
        
        foreach (var prop in propertiesToIgnore)
        {
            schema.Properties?.Remove(prop);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

功能: 忽略敏感属性,不在文档中显示。


# EnumSchemaFilter(枚举过滤器)

文件位置: Swagger.Core/Filters/EnumSchemaFilter.cs

public class EnumSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            schema.Enum.Clear();
            
            foreach (var enumName in Enum.GetNames(context.Type))
            {
                var enumValue = Enum.Parse(context.Type, enumName);
                var description = enumName;
                
                var field = context.Type.GetField(enumName);
                var descAttr = field.GetCustomAttribute<DescriptionAttribute>();
                if (descAttr != null)
                {
                    description = descAttr.Description;
                }
                
                schema.Enum.Add(new OpenApiString($"{(int)enumValue} - {description}"));
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

功能: 在 Swagger 文档中显示枚举的描述和值。


# DescriptionDocumentFilter(描述文档过滤器)

文件位置: Swagger.Core/Filters/DescriptionDocumentFilter.cs

功能: 为 API 文档添加详细描述。


# 🏗️ 依赖注入

# ServiceCollectionExtensions

文件位置: Swagger.Core/ServiceCollectionExtensions.cs

public static class ServiceCollectionExtensions
{
    /// <summary>
    /// 添加 Swagger
    /// </summary>
    public static void AddSwagger(
        this IServiceCollection services, 
        IModuleCollection modules)
    {
        services.AddSwaggerGen(c =>
        {
            // API 版本
            c.SwaggerDoc("v1", new OpenApiInfo
            {
                Title = "DarkM API V1",
                Version = "v1",
                Description = "DarkM 框架 API 文档"
            });

            // 自定义过滤器
            c.DocumentFilter<LowercaseDocumentFilter>();
            c.DocumentFilter<DescriptionDocumentFilter>();
            c.SchemaFilter<EnumSchemaFilter>();
            c.SchemaFilter<IgnorePropertySchemaFilter>();

            // 包含 XML 注释
            var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
            foreach (var xmlFile in xmlFiles)
            {
                c.IncludeXmlComments(xmlFile);
            }
        });
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 💡 使用示例

# 1. 启用 Swagger

appsettings.json:

{
  "Host": {
    "Swagger": true
  }
}
1
2
3
4
5

访问地址: http://localhost:6220/swagger/index.html


# 2. Controller 注释

using System.ComponentModel;
using Microsoft.AspNetCore.Mvc;

/// <summary>
/// 用户管理
/// </summary>
[Description("用户管理")]
[ApiController]
[Route("api/[controller]")]
[ApiVersion("1.0")]
public class UsersController : ControllerBase
{
    private readonly IUserService _userService;

    public UsersController(IUserService userService)
    {
        _userService = userService;
    }

    /// <summary>
    /// 获取用户详情
    /// </summary>
    /// <param name="id">用户 ID</param>
    /// <returns>用户信息</returns>
    /// <response code="200">返回用户信息</response>
    /// <response code="404">用户不存在</response>
    [HttpGet("{id}")]
    [Description("获取用户详情")]
    [ProducesResponseType(typeof(UserDto), 200)]
    [ProducesResponseType(404)]
    public IResultModel<UserDto> Get(int id)
    {
        return ResultModel.Success(_userService.GetById(id));
    }

    /// <summary>
    /// 添加用户
    /// </summary>
    /// <param name="model">用户信息</param>
    /// <returns>操作结果</returns>
    /// <response code="200">添加成功</response>
    /// <response code="400">参数错误</response>
    [HttpPost]
    [Description("添加用户")]
    [ProducesResponseType(200)]
    [ProducesResponseType(400)]
    public async Task<IResultModel> Add([FromBody] UserAddModel model)
    {
        return await _userService.AddAsync(model);
    }

    /// <summary>
    /// 删除用户
    /// </summary>
    /// <param name="id">用户 ID</param>
    /// <returns>操作结果</returns>
    [HttpDelete("{id}")]
    [Description("删除用户")]
    [ProducesResponseType(200)]
    public async Task<IResultModel> Delete([BindRequired] int id)
    {
        return await _userService.DeleteAsync(id);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

# 3. 模型注释

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

/// <summary>
/// 用户添加模型
/// </summary>
public class UserAddModel
{
    /// <summary>
    /// 用户名
    /// </summary>
    [Required(ErrorMessage = "用户名不能为空")]
    [StringLength(50, ErrorMessage = "用户名长度不能超过 50 个字符")]
    [Description("用户名")]
    public string UserName { get; set; }

    /// <summary>
    /// 邮箱
    /// </summary>
    [EmailAddress(ErrorMessage = "邮箱格式不正确")]
    [Description("邮箱")]
    public string Email { get; set; }

    /// <summary>
    /// 状态
    /// </summary>
    [Description("状态")]
    public Status Status { get; set; } = Status.Enabled;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 🔧 权限编码

Swagger 中的权限编码格式:Area_Controller_Action_HttpMethod

接口 权限编码 说明
GET /api/user Admin_User_Query_Get 查询用户
POST /api/user Admin_User_Add_Post 添加用户
DELETE /api/user/{id} Admin_User_Delete_Delete 删除用户
PUT /api/user/{id} Admin_User_Update_Put 更新用户

# 🔍 常见问题

# Q1: Swagger 页面空白?

检查清单:

  1. ✅ 确认 appsettings.jsonSwagger 设置为 true
  2. ✅ 确认项目已生成 XML 文档
  3. ✅ 确认 XML 文件路径正确

解决方案:

<!-- .csproj 文件 -->
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
1
2
3
4
5

# Q2: 如何配置多版本 API?

解决方案:

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "DarkM API V1",
        Version = "v1",
        Description = "DarkM 框架 API 文档 V1"
    });
    
    c.SwaggerDoc("v2", new OpenApiInfo
    {
        Title = "DarkM API V2",
        Version = "v2",
        Description = "DarkM 框架 API 文档 V2"
    });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Q3: 如何隐藏某些接口?

解决方案:

  1. 使用 [ApiExplorerSettings(IgnoreApi = true)]
[ApiExplorerSettings(IgnoreApi = true)]
[HttpGet("internal")]
public IActionResult InternalApi()
{
    // 内部接口,不在 Swagger 中显示
}
1
2
3
4
5
6
  1. 使用 [ExcludeFromDocumentation]
[ExcludeFromDocumentation]
[HttpGet("health")]
public IActionResult HealthCheck()
{
    // 健康检查接口,不在 Swagger 中显示
}
1
2
3
4
5
6

# Q4: 如何配置 JWT 认证?

解决方案:

services.AddSwaggerGen(c =>
{
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });

    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            Array.Empty<string>()
        }
    });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# Q5: 如何自定义 Swagger UI?

解决方案:

app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "DarkM API V1");
    c.RoutePrefix = string.Empty;  // 设置为根路径
    c.DocumentTitle = "DarkM API 文档";
    c.DefaultModelsExpandDepth(2);
    c.DefaultModelExpandDepth(2);
});
1
2
3
4
5
6
7
8

# 📚 相关文档


# 🔗 参考链接


最后更新: 2024-09-20