.NET 9.0 与 Swagger 的集成实践:一步步构建Api文档

引言

在现代API开发中,良好的文档是确保API易用性和可维护性的关键。Swagger(现在也称为OpenAPI)是一个强大的工具,可以自动生成、可视化和测试API文档。本文将详细介绍如何在.NET 9.0项目中集成Swagger,构建专业的API文档。

一、准备工作

1. 创建项目并安装Swashbuckle.AspNetCore包

在.NET 9.0中,我们需要安装以下Swagger相关包:

bash 复制代码
dotnet add package Swashbuckle.AspNetCore

二、基本Swagger配置

1. 配置Swagger服务

在.NET 9.0中,我们可以在Program.cs文件中配置Swagger服务。以下是基本配置:

csharp 复制代码
// Program.cs
if (env.IsDevelopment() || appConfig.Swagger.Enable)
{
    // 注册Swagger生成器和端点资源管理器
    services.AddEndpointsApiExplorer();
    services.AddSwaggerGen(options =>
    {
        // 配置Swagger文档
        options.SwaggerDoc("v1", new OpenApiInfo
        {
            Title = "API文档",
            Version = "v1",
            Description = "这是一个.NET 9.0 Web API项目"
        });
    });
}
2. 配置Swagger中间件

接下来,我们需要在请求管道中添加Swagger中间件:

csharp 复制代码
// Program.cs
if (env.IsDevelopment() || appConfig.Swagger.Enable)
{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "API文档 v1");
        c.DocumentTitle = "接口文档";
    });
}

三、高级Swagger配置

1. Swagger分组配置

为了更好地组织API文档,我们可以使用Swagger分组功能。首先,创建一个扩展方法来配置Swagger分组:

csharp 复制代码
// SwaggeServiceExtension.cs
public static void AddSaggerGroup(this SwaggerGenOptions options)
{
    // 配置接口阐述文档
    options.SwaggerDoc("PrefaceGroup", new OpenApiInfo
    {
        Title = "接口阐述",
        Description = "详细的API使用说明",
        Version = "V1"
    });
    
    // 从程序集中扫描SwaggeGroupAttribute属性,自动生成API分组
    GetSwaggerGroupInfo().ForEach(f =>
    {
        options.SwaggerDoc(f.GroupName, new OpenApiInfo
        {
            Title = f.Title,
            Version = f.Version,
            Description = f.Description
        });
    });
    
    // 配置文档包含规则
    options.DocInclusionPredicate((docName, apiDescription) =>
    {
        if (docName == "NoGroup")
        {
            // 当分组为NoGroup时,只要没加特性的都属于这个组
            return string.IsNullOrEmpty(apiDescription.GroupName);
        }
        else
        {
            return apiDescription.GroupName == docName;
        }
    });
}
2. 配置Swagger UI分组

接下来,创建一个扩展方法来配置Swagger UI分组:

csharp 复制代码
// SwaggeServiceExtension.cs
public static void UseGroupSagger(this IApplicationBuilder app)
{
    app.UseSwaggerUI(c =>
    {
        c.DocumentTitle = "接口文档";
        c.SwaggerEndpoint("/swagger/PrefaceGroup/swagger.json", "接口阐述");
        
        // 添加自动生成的API分组端点
        GetSwaggerGroupInfo().ForEach(f =>
        {
            c.SwaggerEndpoint($"/swagger/{f.GroupName}/swagger.json", f.Title ?? f.GroupName);
        });
        
        // 配置文档折叠方式
        c.DocExpansion(DocExpansion.None);
    });
}
3. 使用Swagger分组属性

创建一个SwaggeGroupAttribute属性,用于标记控制器所属的分组:

csharp 复制代码
// SwaggeGroupAttribute.cs
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class SwaggeGroupAttribute : Attribute, IApiDescriptionGroupNameProvider
{
    public string GroupName { get; set; }
    public string Title { get; set; }
    public string Version { get; set; }
    public string Description { get; set; }
    
    public SwaggeGroupAttribute(string groupName, string title, string version, string description = "")
    {
        GroupName = groupName;
        Title = title;
        Version = version;
        Description = description;
    }
}

然后,在控制器上使用该属性:

csharp 复制代码
[ApiController]
[Route("[controller]")]
[SwaggeGroup("UserGroup", "用户管理", "v1", "用户相关API")]
public class UserController : ControllerBase
{
    // API方法
}
4. Swagger过滤器

Swagger提供了多种过滤器,可以自定义API文档的生成。以下是一些常用的过滤器:

4.1 枚举架构过滤器

增强枚举类型的描述:

csharp 复制代码
// EnumSchemaFilter.cs
public class EnumSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            schema.Enum.Clear();
            Enum.GetNames(context.Type).ToList().ForEach(name =>
            {
                var enumMember = context.Type.GetMember(name).First();
                var descriptionAttribute = enumMember.GetCustomAttribute<DescriptionAttribute>();
                var enumValue = Enum.Parse(context.Type, name);
                
                schema.Enum.Add(new OpenApiString($"{enumValue} - {descriptionAttribute?.Description ?? name}"));
            });
        }
    }
}
4.2 路径驼峰命名过滤器

将API路径转换为驼峰命名格式:

csharp 复制代码
// PathCamelCasenFilter.cs
public class PathCamelCasenFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        var paths = swaggerDoc.Paths.ToDictionary(entry => entry.Key, entry => entry.Value);
        swaggerDoc.Paths.Clear();
        
        foreach (var path in paths)
        {
            var newPath = string.Join("/", path.Key.Split('/').Select(segment =>
            {
                if (segment.StartsWith("{") && segment.EndsWith("}"))
                {
                    var paramName = segment.Substring(1, segment.Length - 2);
                    return "{" + char.ToLower(paramName[0]) + paramName.Substring(1) + "}";
                }
                return segment;
            }));
            
            swaggerDoc.Paths[newPath] = path.Value;
        }
    }
}
4.3 Swagger忽略属性

用于标记不需要在文档中显示的属性:

csharp 复制代码
// SwaggerIgnoreAttribute.cs
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class SwaggerIgnoreAttribute : Attribute
{
}
5. 注册Swagger过滤器

Program.cs中注册这些过滤器:

csharp 复制代码
// Program.cs
services.AddSwaggerGen(options =>
{
    // 添加Swagger分组
    options.AddSaggerGroup();
    
    // 注册过滤器
    options.OperationFilter<SwaggerIgnoreFilter>();
    options.OperationFilter<AddHeaderParameterOperationFilter>();
    options.SchemaFilter<EnumSchemaFilter>();
    options.OperationFilter<ValidateRequiredOperationFilter>();
    options.DocumentFilter<PathCamelCasenFilter>();
    
    // 配置自定义操作ID
    options.CustomOperationIds(apiDesc =>
    {
        var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
        return controllerAction!.ControllerName + "-" + controllerAction.ActionName;
    });
    
    // 包含XML注释
    string[] xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
    if (xmlFiles.Length > 0)
    {
        foreach (var xmlFile in xmlFiles)
        {
            options.IncludeXmlComments(xmlFile, true);
        }
    }
    
    // 配置参数驼峰命名
    options.DescribeAllParametersInCamelCase();
});

四、条件启用Swagger

在实际项目中,我们可能只希望在特定环境或特定条件下启用Swagger。可以通过以下方式实现:

csharp 复制代码
// Program.cs
// 仅在开发环境或配置文件中启用Swagger时启用
if (env.IsDevelopment() || appConfig.Swagger.Enable)
{
    // 配置Swagger服务
    services.AddSwaggerGen(options =>
    {
        // Swagger配置
    });
    
    // 配置Swagger中间件
    app.UseSwagger();
    app.UseGroupSagger();
}

五、配置文件管理

为了更好地管理Swagger配置,我们可以将Swagger配置添加到appsettings.json文件中:

json 复制代码
// appsettings.json
{
  "Swagger": {
    "Enable": true,
    "Title": "API文档",
    "Version": "v1"
  }
}

然后,创建一个配置类来映射这些配置:

csharp 复制代码
// AppConfig.cs
public class AppConfig
{
    public SwaggerConfig Swagger { get; set; } = new SwaggerConfig();
}

public class SwaggerConfig
{
    public bool Enable { get; set; } = false;
    public string Title { get; set; } = "API文档";
    public string Version { get; set; } = "v1";
}

六、测试和验证

配置完成后,我们可以运行项目并访问Swagger UI界面。默认情况下,Swagger UI的地址是http://localhost:5000/swagger

在Swagger UI中,我们可以:

  1. 查看API文档的分组结构
  2. 查看每个API的详细信息,包括请求参数、响应参数等
  3. 直接在界面上测试API
相关推荐
唐青枫1 小时前
C#.NET Record Struct 完全解析:语法、语义与最佳实践
c#·.net
时光追逐者11 小时前
分享5款.NET开源免费的Redis客户端组件库
数据库·redis·开源·c#·.net·.net core
张人玉1 天前
Prism Template Pack 完整使用示例(VS2022 + .NET 8 + DryIoc)
.net·wpf·prism
j***63081 天前
四大.NET ORM框架深度对比:EF Core、SqlSugar、FreeSql与Dapper的性能、功能与适用场景
.net
我是唐青枫2 天前
C#.NET 范围与索引(Range、Index)完全解析:语法、用法与最佳实践
c#·.net
深海潜水员2 天前
【MonoGame游戏开发】| 牧场物语实现 第一卷 : 农场基础实现 (下)
vscode·游戏·c#·.net·monogame
时光追逐者3 天前
Visual Studio 2026 现已正式发布,更快、更智能!
ide·c#·.net·visual studio
用户7227868123444 天前
.NET 实现雪花算法:高效生成分布式唯一 ID
.net