Asp.Net Core遇到Swagger(四)-Swashbuckle技巧c篇

2023-11-14

一、前言

Swashbuckle技巧b篇,与Action相关的配置和操作,此处为c篇内容。

blog-jrz-swagger-header

二、实践技巧

2.9 忽略过时控制器和过时Action

1)配置服务

编辑ConfigureServices函数中的AddSwaggerGen函数,

services.AddSwaggerGen(c =>
{
    ...
    #region 自定义DocInclusionPredicate判定规则
    //options.DocInclusionPredicate((docName, apiDesc) => {
    //    //判定当前执行是否为函数对象
    //    if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo))
    //        return false;
    //    //获取函数对应的自定义特性ApiVersionAttribute对应的版本集合
    //    var versions = methodInfo.GetCustomAttributes(true)
    //    .OfType<ApiVersionAttribute>()
    //    .SelectMany(x => x.Versions);
    //    //判定版本集合中是否与当前文档匹配
    //    return versions.Any(x => $"v{x}" == docName);
    //});
    #endregion

    #region 忽略过时特性
    //忽略标记过时的Action
    options.IgnoreObsoleteActions();
    //忽略标记过时的Properties
    options.IgnoreObsoleteProperties();
    #endregion
    ...
};
2)添加案例控制器

新建控制器IgnoreObsoleteController,内容如下:

namespace swaggertestbase.Controllers.v1
{
    /// <summary>
    /// 忽略函数控制器
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    public class IgnoreObsoleteController : ControllerBase
    {
        /// <summary>
        /// 获取忽略函数数据
        /// </summary>
        /// <returns>返回结果</returns>
        [Obsolete]
        [HttpGet]
        public string Get()
        {
            return "IgnoreObsolete";
        }
        
        [HttpGet("{id}")]
        //直接直接使用ApiExplorerSettings设置属性IgnoreApi = true
        //在当前项目中该配置无效
		[ApiExplorerSettings(IgnoreApi = true)]
		public string GetById(int id)
        {
            return "IgnoreObsolete";
        }
    }
}

运行效果如下,在v1组中并不存在对应的控制器以及对应过时的函数。

Swagger-IgnorObsolete

2.10 按照约定选择Action函数

1)自定义约定实现类

新建类ApiExplorerGetsOnlyConvention,实现IActionModelConvention接口,进行ActionModelConvention的自定义规则实现。

/// <summary>
/// 自定义实现只显示Get请求的Action模型
/// </summary>
public class ApiExplorerGetsOnlyConvention : IActionModelConvention
{
    public void Apply(ActionModel action)
    {
        //依据请求是否为get请求处理是是否参与apijson的数据接口生成
        action.ApiExplorer.IsVisible = action.Attributes.OfType<HttpGetAttribute>().Any();
    }
}
2)添加约定到服务配置
services.AddControllers(configure => {
    //添加自定义apiexplor.groupname控制器模型属性
    //configure.Conventions.Add(new ApiExplorerGroupVersionConvention());
    //自定义实现只显示Get请求的Action模型
    configure.Conventions.Add(new ApiExplorerGetsOnlyConvention());
});

在控制器WeatherForecastController中添加一个Post请求函数,

/// <summary>
/// 获取Post数据
/// </summary>
/// <returns>处理结果</returns>
[HttpPost]
public string Post()
{
    return "处理结果";
}

运行效果:
Swagger-ActionModelConvention

2.11 自定义操作标签

默认Tag分组是以控制器名称为依据进行划分,也可以通过TagActionsBy函数进行配置。

1)默认分组

Swagger-DefaultTags

2)自定义Tags分组

修改ConfigureServicesAddSwaggerGen对应配置,以下为依据Action的请求方法进行分组的案例,需要注意的是IncludeXmlComments函数,需要使用默认配置,而不是设置IncludeXmlComments第二参数为true

services.AddSwaggerGen(options =>
{
    ...
    #region 添加xml注释文件描述性信息
    //获取当前执行程序集名称+.xml,作为实际xml注释文件名称
    string filename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    //拼接路径-路径间隔符由系统决定
    string path = System.IO.Path.Combine(System.AppContext.BaseDirectory, filename);
    //添加xml注释文件到swaggergen中用于生成api json
    //此时需要选择使用该函数的默认配置
    options.IncludeXmlComments(path);
    #endregion

    #region 自定义Tags
    options.TagActionsBy(apidescr => {
        return new string[] {
        apidescr.HttpMethod
        };
    });
    #endregion
    ...
};
                       
services.AddControllers(configure => {
    //添加自定义apiexplor.groupname控制器模型属性
    //configure.Conventions.Add(new ApiExplorerGroupVersionConvention());
    //自定义实现只显示Get请求的Action模型
    //configure.Conventions.Add(new ApiExplorerGetsOnlyConvention());
});

运行效果:
Swagger-CustomTags

2.12 自定义Action排序操作

默认情况下,Action能够按Swagger规范,在添加到分组之前进行排序操作,也可自定义排序规则,修改ConfigureServicesAddSwaggerGen对应配置,此处以自定义排序规则Controller请求方法进行排序。

#region 自定义Tags
options.TagActionsBy(apidescr => {
    return new string[] {
    apidescr.HttpMethod
    };
});
#endregion

#region  自定义Tags排序
options.OrderActionsBy(apidesc =>
{
    //自定义Tag内的Action排序
    return $"{apidesc.ActionDescriptor.RouteValues["controller"]}_{apidesc.HttpMethod}";
});
#endregion

运行效果:
Swagger-CustomTagOrder

2.13 自定义架构id

如果在文档生成器遇到复杂的传入参数或响应类型,生成器会自动生成相应Json Schema,并将其添加到全局Components/Schemas字典中。

还是以天气类WeatherForecast,默认情况下,Api Json对应请求链接http://localhost:5000/v1/swaggerapi.json内容大致如下:

{
  "paths": {
    "/WeatherForecast": {
      "get": {
        "tags": [
          "GET"
        ],
        "summary": "获取天气预报信息",
        "responses": {
          "201": {
            "description": "请求成功并且服务器创建了新的资源",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    // #/components/schemas/{schemasid}
                    "$ref": "#/components/schemas/WeatherForecast"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "WeatherForecast": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "日期",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "天气预报实体"
      }
    }
  }
}

修改服务中ConfigureServices的配置,自定义标识的生成规则CustomSchemaIds

public void ConfigureServices(IServiceCollection services)
{
       services.AddSwaggerGen(
       		options =>
            {
                #region 自定义架构Id
                // 输出对应类型全名称
    			options.CustomSchemaIds(schema => schema.FullName);
    			#endregion
            }
       );
}

运行后,对应输出的Json结构如下:

{
  "paths": {
    "/WeatherForecast": {
      "get": {
        "tags": [
          "GET"
        ],
        "summary": "获取天气预报信息",
        "responses": {
          "201": {
            "description": "请求成功并且服务器创建了新的资源",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "array",
                  "items": {
                    // #/components/schemas/{schemasid}
                    "$ref": "#/components/schemas/swaggertestbase.WeatherForecast"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      // {schemasid}
      "swaggertestbase.WeatherForecast": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "日期",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "天气预报实体"
      }
    }
  }
}

2.14 覆盖特定类型架构[不常用]

需要对特定类型进行指定序列化处理时,可以通过自定义架构序列化类型处理。

数据实体类:

/// <summary>
/// 天气预报实体
/// </summary>
public class WeatherForecast
{
    /// <summary>
    /// 日期
    /// </summary>
    public DateTime Date { get; set; }
    /// <summary>
    /// 温度-摄氏度
    /// </summary>
    public int TemperatureC { get; set; }
    /// <summary>
    /// 温度-华摄氏度
    /// </summary>
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    /// <summary>
    /// 描述
    /// </summary>
    public string Summary { get; set; }
}

请求http://localhost:5000/v1/swaggerapi.json,原始Json架构如下:

 "components": {
    "schemas": {
      "WeatherForecast": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "日期",
            "format": "date-time"
          },
          "temperatureC": {
            "type": "integer",
            "description": "温度-摄氏度",
            "format": "int32"
          },
          "temperatureF": {
            "type": "integer",
            "description": "温度-华摄氏度",
            "format": "int32",
            "readOnly": true
          },
          "summary": {
            "type": "string",
            "description": "描述",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "天气预报实体"
      }
    }
  }

修改ConfigureServices中的AddSwaggerGen,设定类型序列化的架构为字符串。

services.AddSwaggerGen(
    options =>
    {
        #region 覆盖特定类型架构
        // 指定对应的实体类型,类型架构配置
        options.MapType<WeatherForecast>(() => new Microsoft.OpenApi.Models.OpenApiSchema { Type = "string" });
        #endregion
    }
    );

设置以后,对应的类型在架构中,无生成,目前无考虑深究原因,运行效果如下:

Swagger-overrideschame

2.15 使用过滤器扩展生成器

1)操作过滤器

Swashbuckle会检索每一个Asp.Net Core中的每一个ApiDescription,从中提取到对应的OpenApiOperation,对应OpenApiOperation类型和ApiDescription能够通过操作过滤器列表实现传递。以包含权限认证特性,响应中401响应状态的操作过滤器为例。

创建类AuthResponsesOperationFilter实现IOperationFilter

public class AuthResponsesOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var customAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true)
            .Union(context.MethodInfo.GetCustomAttributes(true))
            .OfType<AuthorizeAttribute>();

        if (customAttributes.Any())
        {
            operation.Responses.Add("401", new OpenApiResponse { Description = "UnAuthorized" });
        }
    }
}

给控制器中WeatherForecastController对应Post函数添加特性Authorize

/// <summary>
/// 天气预报服务
/// </summary>
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    ........
    /// <summary>
    /// 获取Post数据
    /// </summary>
    /// <returns>处理结果</returns>
    [HttpPost]
    [Authorize]
    public string Post()
    {
        return "处理结果";
    }
    ........
}

添加到动作过滤器列表中,

services.AddSwaggerGen(
    options =>
    {
		#region 添加权限认证响应操作过滤器
		options.OperationFilter<AuthResponsesOperationFilter>();
		#endregion
    }
);

运行效果如下:

Swagger-Operationfilter

需要注意的是,过滤器管道是DI感知的。 可以使用构造函数参数创建过滤器,只要参数类型已在DI框架中注册,则它们将在过滤器实例化时自动注入。

2)架构过滤器

Swashbuckle为控制器操作公开的每个参数、响应和属性类型生成 Swagger 样式的 JSONSchema。 生成后,它通过配置的架构过滤器列表传递架构和类型。

创建枚举类型,

/// <summary>
/// 自定义枚举
/// </summary>
public enum MyEnum
{
    A,
    B,
    C
}

创建SchemaFilterController控制器,

[Route("api/[controller]")]
[ApiController]
public class SchemaFilterController : ControllerBase
{
    /// <summary>
    /// 获取SchemaFilter过滤器数据
    /// </summary>
    /// <param name="my">枚举参数</param>
    [HttpGet]
    public void Get(MyEnum my)
    { 
        
    }
}

自定义类AutoRestSchemaFilter,实现ISchemaFilter

/// <summary>
/// 自动设置架构过滤器
/// </summary>
public class AutoRestSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        var type = context.Type;
        if (type.IsEnum)
        {
            schema.Extensions.Add("x-ms-enum", new OpenApiObject()
            {
                ["name"] = new OpenApiString(type.Name),
                ["modelAsString"] = new OpenApiBoolean(true)
            });
        }
    }
}

添加到架构过滤器中,

....
    services.AddSwaggerGen(
                options =>
    {
        #region 添加自定义架构过滤器
		options.SchemaFilter<AutoRestSchemaFilter>();
		#endregion
    });
....

访问http://localhost:5000/v1/swaggerapi.json,可以看到对应结构如下如下,x-ms-enum在对应类型的架构尾部。

{
    "components": {
    "schemas": {
      "MyEnum": {
        "enum": [
          0,
          1,
          2
        ],
        "type": "integer",
        "description": "自定义枚举",
        "format": "int32",
        "x-ms-enum": {
          "name": "MyEnum",
          "modelAsString": true
        }
      }
    }
  }
}

通过上述例子,可以看出,对于枚举等特殊类型,实际可以通过自定义Json schema的方式实现对应字段值的备注含义。

3)文档过滤器

Document Filters在遵守OpenApi的规范前提下,可以通过文档过滤器对文档进行任意有效的Swagger Json。例如为当前文档添加额外的Tags,自定义过滤器TagDescriptionsDocumentFilter,实现IDocumentFilter

/// <summary>
/// Tag描述文档过滤器
/// </summary>
public class TagDescriptionsDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        swaggerDoc.Tags = new List<OpenApiTag> { 
            new OpenApiTag{ 
               Name ="Pages",
               Description = "分页类"
            },
            new OpenApiTag{
               Name ="Tests",
               Description = "测试类"
            }
        };
    }
}

添加到现有的文档过滤器中,

public void ConfigureServices(IServiceCollection services)
{
    services.AddSwaggerGen(
        options =>
        {
            //忽略部分内容
            #region 添加自定义文档过滤器
            options.DocumentFilter<TagDescriptionsDocumentFilter>();
            #endregion
            //忽略部分内容
        }
        );
}

请求http://localhost:5000/v1/swaggerapi.json,在返回结果中能够看到如下部分结构:

{
    //忽略无关项
    "tags": [
    {
      "name": "Pages",
      "description": "分页类"
    },
    {
      "name": "Tests",
      "description": "测试类"
    }
  ]
}

后续文章将讲解为Swagger添加安全验证。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Asp.Net Core遇到Swagger(四)-Swashbuckle技巧c篇 的相关文章

随机推荐

  • LayUi做登录注册

    LayUi登录注册页面附代码 登录页面 注册页面 附加CSS JS代码 JS代码 CSS代码 登录页面 下面展示登录页面 代码如下
  • STM32外设系列—BH1750

    文章目录 一 BH1750简介 二 BH1750原理图 三 BH1750数据手册 3 1 指令集 3 2 IIC通信读 写 四 BH1750程序设计 4 1 IIC程序 4 2 BH1750初始化程序 4 3 读取BH1750测量结果 4
  • 免费代码开发辅助AI工具CodeWhisperer、CodeGeeX、Codeium

    vscode应用市场可以直接搜索安装 vscode安装后左侧状态栏图标 注意 三款使用都需要翻墙注册 使用基本也是翻墙网络下使用 CodeGeeX国产 支持代码解释 聊天框 Codeium也支持代码解释 聊天框 按Tab是接受ai代码工具推
  • C# winForm 图片预览

    ImageZoomMainForm cs using System using System Collections Generic using System ComponentModel using System Data using S
  • BUUCTF MISC刷题笔记(二)

    BUUOJ Misc WUSTCTF2020 spaceclub 派大星的烦恼 SCTF2019 电单车 hashcat UTCTF2020 zero CTF2019 otaku 湖南省赛2019 Findme 1 png 2 png 3
  • Win11+VS2019配置YOLOX

    基本环境 操作系统 Windows 编译软件 Visual Studio 2019 Python版本 3 8 编译流程 1 使用如下指令下载YOLOX源码 git clone recursive https github com Megvi
  • Sentinel数据处理-基于snap软件

    目录 1 sentinel卫星数据介绍 1 1 sentinel1 1 2 sentinel2 1 3 sentinel3 2 sentinel卫星数据预处理 2 1 snap软件下载 2 2 sentinel2 数据下载 3 sentin
  • Android快捷键之代码自动对齐

    一 背景 你是否有在为代码格式比较乱而烦心呢 二 解决办法 Android studio使用 Ctrl Alt L 注 快捷键可以格式化代码 也可以理解为让代码自动对齐 也可以使用一些插件处理代码格式问题 注意 这快捷键在没有其他应用的快捷
  • Vue3中ref,toRef,toRefs的区别与用法

    ref vs toRef 如果利用ref函数将某个对象中的属性变成响应式数据 对其进行修改是不会影响原始数据的 利用toRef进行上方操作 对数据的修改是响应式的 toRef vs toRefs toRef 创建一个ref对象 其value
  • sbit在c语言中的作用,sbit是什么意思

    sbit 词语概况 定义特殊功能寄存器的位变量 bit和sbit都是C51扩展的变量类型 典型应用是 sbit P0 0 P0 0 即定义P0 0为P0口的第1位 以便进行位操作 用法 在C语言里 如果直接写P1 0 C编译器并不能识别 而
  • layui中监听单击和双击事件的使用

    作者 张铭标 撰写时间 2019年 6月27日 平时在做数据回填的时候 我们需要用到layui中的监听单击和双击事件来进行数据的获取和回填 具体的使用如图所示 从图中看出这是监听单击事件 一开始需要先引入layui插件就不用多说了 先写一个
  • python中argsort函数用法

    最近在学NMS算法 刚好看到了argsort 函数 特记录下 供自己以后查询 如有不足 欢迎评论区指正 一维数组的argsort 函数用法 import numpy as np a np array 5 3 4 7 2 9 b a args
  • Linux下matlab打开出现启动桌面时错误

    Ubuntu下matlab程序无法直接打开 出现一个 启动桌面时错误 的弹窗 以及提示一堆java似的错误 如下 其实还是权限的问题 如果sudo matlab可以运行 但是可不可以普通权限正常终端命令matlab运行程序呢 其实一条命令即
  • ARM(IMX6U)裸机模仿STM32驱动开发实验(定义外设结构体)

    参考 Linux之ARM IMX6U 裸机模仿STM32驱动开发格式 作者 一只青木呀 发布时间 2020 08 15 12 11 56 网址 https blog csdn net weixin 45309916 article deta
  • 信息安全技术之9软件保护技术测试卷1

    信息安全技术之9软件保护技术测试卷2 一 多选题 二 判断题 叮嘟 这里是小啊呜的学习课程资料整理 好记性不如烂笔头 今天也是努力进步的一天 一起加油进阶吧 一 多选题 1 此题归属第9讲 下列工具哪些不属于静态分析工具 A OllyDbg
  • 搭建高可用mongodb集群(二)—— 副本集

    在上一篇文章 搭建高可用MongoDB集群 一 配置MongoDB 提到了几个问题还没有解决 主节点挂了能否自动切换连接 目前需要手工切换 主节点的读写压力过大如何解决 从节点每个上面的数据都是对数据库全量拷贝 从节点压力会不会过大 数据压
  • spring boot 打包所有文件到classes,maven配置

  • [585]爬虫

    文章目录 1 目标网站 2 反爬虫机制 3 解决 4 上代码 字体解密相关资源 总结 目前已知的几个字体反爬的网站是猫眼 汽车之家 天眼查 起点中文网等等 本文用到的第三方库 fontTools 安装 pip install fontToo
  • JVM分析工具

    JVM在运行过程中 我们可以利用各种工具对JVM进行分析 这是性能调优的利器 可以通过各种工具了解在系统运行过程中 在JVM底层到底发生了什么 JVM分析工具一般分为两种 一种是命令行工具 一种是图形界面工具 JVM分析工具 JDK自带的命
  • Asp.Net Core遇到Swagger(四)-Swashbuckle技巧c篇

    文章目录 一 前言 二 实践技巧 2 9 忽略过时控制器和过时 Action 1 配置服务 2 添加案例控制器 2 10 按照约定选择 Action 函数 1 自定义约定实现类 2 添加约定到服务配置 2 11 自定义操作标签 1 默认分组