从零开始:如何在.NET Core Web API中完美配置Swagger文档

news2024/12/18 1:51:41

目录

新建项目

RestFul

Swagger配置

注释展示

版本控制

Token传值

方法封装


新建项目

打开visual studio创建新项目,这里我们选择.net core web api模板,然后输入项目名称及其解决方案创建新项目

这里使用配置一些其他信息,根据自己情况进行选择:

创建好项目之后我们可以看到 web api 模板运行的项目,相比于MVC模式开发的项目,初始文件是保留原有的控制器文件但是删除了模型和视图文件,而且还加上了两个文件,文件的作用相当于测试用例一一可以模拟发起请求,如下所示:

我们直接运行该项目,可以看到我们打开了一个Swagger文件,对于后端小白来说可能不太熟悉这个文件的作用,但是对于前端开发者来讲可谓是非常熟悉的东西,前端开发调用接口就需要经常和这个文件打交道,如下所示:

我们除了可以在Swagger上测试接口,也可以在本地代码的测试用例处点击发起请求进行测试:

这里做一个演示,比如说我们想在Swagger文档中新增一组接口的话,我们可以在控制器文件中设置一下get、post、delete、put请求操作,如下我们将原本的文件复制一份然后命名为First,然后设置一下接口类型,如下所示:

重新运行我们的项目然后打开Swagger,可以看到我们创建的一组接口成功出现了,这里接口的组名可以看到是 FirstController.cs 文件中Controller的前缀,非常好识别:

RestFul

        背景:近些年来随着移动互联网的发展,前端设备层出不穷(手机、平板、桌面电脑、其他专用设备..),因此必须有一组统一的机制方便不同的前端设备与后端进行通信,于是RestFul诞生了,它可以通过一套统一的接口为Web,iOS和Android等各种各样的终端提供服务。

        特点:RestFul把控制器作为维度当成一块资源,对于这个资源会进行增删改查等各种当作,这些动作必须都得有唯一的URL地址来匹配请求的Method的类型(get、post、put、delete),本质上就是用URL定位资源,用HTTP(get、post、put、delete)描述操作。说白了就是一种软件架构设计风格而不是标准,只是提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁有层次,更易于实现缓存等机制。

比如上文我们在控制器文件中设置了一组接口,如果我们再在文件中添加比如说一个get接口请求,运行项目其实是会报错的,为什么?就是因为这两个get请求的地址都是一样的,编辑器没法识别到底哪个get请求是你想要的,为了区分我们必须设置唯一的URL地址来避免报错,如下:

重新运行项目,可以看到我们在First组当中又新增了一个新的get请求,且两个get请求的URL路径是不一致的,如下所示:

对于路由约束的类型我们可以参考如下表格,这些都可以作为接口传参的一个类型限定:

限制示例匹配示例说明
int{id: int}123456789, -123456789匹配任何整数
bool{active: bool}true, false匹配true或false,忽略大小写
datetime{dob: datetime}2024-12-11,2024-12-12 7:32pm匹配满足datetime类型的值
decimal{price: decimal}49.99, -1,000.01匹配满足decimal类型的值
double{height: double}1234, -1001.01e8匹配满足double类型的值
float{height: float}1234, -1001.01e8匹配满足float类型的值
long{ticks: long}123456789, -123456789匹配满足long类型的值
minlength(value){usename: minlength(4)}KOBE字符串长度不能小于4个字符
maxlength(value){filename: maxlength(8)}CURRY字符串长度不能超过8个字符
length(value){filename: length(12)}somefile.txt字符串长度必须是12个字符
length(min,max){filename: length(8,16)}somefile.txt字符串长度必须介于8和16之间
min(value){age: min(18)}20整数值必须大于18
max(value){age: max(120)}119整数值必须小于120
range(min, max){age: range(18, 120)}100整数值必须介于18和120之间
alpha{name: alpha}Rick字符串必须由一或多a-z字母组成
regex(expression){ssn:regex(^\d{3})}3字符串必须匹配指定的正则
required

Swagger配置

        虽然上面我设置了Swagger并成功运行了,但是设想一个场景,如果你是后端你写的代码你当然看的懂,生成的Swagger接口也是知道是什么意思,但是你把这个Swaager丢给前端,前端是否看的懂呢?如果看不懂是不是还要找后端沟通,这样就增加了时间成本。所以后端不仅仅要不接口写对,还要把Swagger文档写好,这里我们就需要对其进行相应配置,争取让其他人看懂自己写的接口,这才是真正意义上一名后端应该做的事情,如下所示:

注释展示

注释是很重要的,当我们写完一个接口之后我们就需要对这个接口的作用进行注释,用来告诉前端后端给的这个接口作用和意义是什么,如何设置Swagger注释展示呢?请往下看:

如下我们给接口代码写下注释,注释的快捷键是///,也就是三个斜杠即可生成,然后右键项目点击属性,勾选文档文件这个复选框:

我们右键项目重新生成解决方案然后打开我们的项目资源管理目录,可以看到在我们项目的obj目录下的最里层有生成了一个xml文件,右键选择文本打开可以看到我们的注释就在里面:

接下来如果说我们想把注释展示到Swagger文档中的话,我们需要来到入口文件Program.cs对我们的Swagger进行一个配置,给原本的AddSwaggerGen添加一个配置对象,代码如下:

builder.Services.AddSwaggerGen(option => {
    #region 注释展示
    {
        // 获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)
        string basePath = AppContext.BaseDirectory;
        string xmlPath = Path.Combine(basePath, "netCoreWebApi.xml");
        option.IncludeXmlComments(xmlPath);
    }
    #endregion
});

回到Swagger文档中可以看到我们的注释已经成功的被渲染出来了,方便前端的理解:

版本控制

随着项目不断升级和开发的过程中,我们还可能需要去对项目进行开发多个版本,但是版本之间的Swagger是不同的,不会放置在同一个Swagger文档下面,我们打开Swagger文档也能看到右上角有个下拉框,其就是支持不同的版本的切换的,如何做?请往下看:

为了方便不同版本的切换,这里我们直接在解决方案中新建项目设置一个独立的文件夹出来,因为待会我们还要对其作一个扩展,所以这里我们选择一个类库即可,如下:

生成的文件我们重命名为 ApiVersionInfo ,然后设置静态成员V1到V5表明版本有5个,如下所示:

我们来到入口文件Program.cs文件处,这里我们开始设置支持Swagger版本控制的代码,这里我们借助 System.Reflection 中的FieldInfo反射机制中的类型,来获取类型ApiVersionInfo中的所有字段信息,然后通过OpenApiInfo来描述Swagger文档的元数据及包含了有关API的关键信息,比如标题、版本、描述等,如下所示:

builder.Services.AddSwaggerGen(option => {
    #region 注释展示
    {
        // 获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)
        string basePath = AppContext.BaseDirectory;
        string xmlPath = Path.Combine(basePath, "netCoreWebApi.xml");
        option.IncludeXmlComments(xmlPath);
    }
    #endregion
    #region 支持Swagger版本控制
    {
        foreach (FieldInfo filed in typeof(ApiVersionInfo).GetFields())
        {
            option.SwaggerDoc(filed.Name, new OpenApiInfo()
            {
                Title = $"netCoreWebApi API {filed.Name}",
                Version = filed.Name,
                Description = $"netCoreWebApi API {filed.Name} 版本"
            });
        }
    }
    #endregion
});

接下来配置Swagger UI使得每个API版本都有一个对应的Swagger UI页面,具体来说它会为每个API版本动态创建一个Swagger UI的入口从而允许用户查看不同版本的API文档,如下:

接下来我们来到编写接口代码的控制器文件,给不同版本设置如下代码,作用是将特定的API控制器或者方法标记为属于某个版本组,从而使得Swagger等工具能够按版本组织和展示API文档:

最终呈现的效果如下所示:

Token传值

如果项目的接口需要授权才能被访问的话,这里我们就需要通过token传值的方式来进行鉴权才能调试接口,如何做呢?请往下看:

这里我们仍然在Swagger配置函数中设置token传值以及添加对应的安全要求,如下所示:

#region 支持token传值
{
    option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
    {
        Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"", // 描述
        Name = "Authorization", // 授权名称
        In = ParameterLocation.Header, // 授权位置,放在头信息进行传值
        Type = SecuritySchemeType.ApiKey, // 授权类型
        BearerFormat = "JWT", // 格式是JWT
        Scheme = "Bearer"
    });
    // 添加安全要求
    option.AddSecurityRequirement(new OpenApiSecurityRequirement()
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference()
                {
                    Id = "Bearer", // 必须和上面一致
                    Type = ReferenceType.SecurityScheme
                }
            },
            new string[] { }
        }
    });
}
#endregion

运行项目来到Swagger文档中,可以看到我们已经成功添加了身份验证,这里我们输入对应的JWT格式即可,如下所示我们输入token之后发起请求,如下已经带上了我们设置的token:

方法封装

根据上面对Swagger的配置,可以看到我们对Swagger的配置基本上都写在了入口Program.cs文件当中,这样就显得非常的冗余,入口文件代码量太多了,这里我们可以将对Swagger的配置抽离到我们创建的类库当中,新建一个文件夹用于专门存放Swagger配置的东西,如下所示:

这里设置一个函数然后把IServiceCollection设置为Service的类型,该类型用于配置依赖注入容器的接口,通常为Swagger配置服务,我们直接把入口文件当中配置Swagger的代码直接粘贴过来:

using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;

namespace netCoreWebApi.WebCore.SwaggerExt
{
    public static class SwaggerExtension
    {
        public static void AddSwaggerExtension(this IServiceCollection Service)
        {
            Service.AddEndpointsApiExplorer();
            Service.AddSwaggerGen(option => {
                #region 注释展示
                {
                    // 获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)
                    string basePath = AppContext.BaseDirectory;
                    string xmlPath = Path.Combine(basePath, "netCoreWebApi.xml");
                    option.IncludeXmlComments(xmlPath);
                }
                #endregion
                #region 支持Swagger版本控制
                {
                    foreach (FieldInfo filed in typeof(ApiVersionInfo).GetFields())
                    {
                        option.SwaggerDoc(filed.Name, new OpenApiInfo()
                        {
                            Title = $"netCoreWebApi API {filed.Name}",
                            Version = filed.Name,
                            Description = $"netCoreWebApi API {filed.Name} 版本"
                        });
                    }
                }
                #endregion
                #region 支持token传值
                {
                    option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                    {
                        Description = "JWT授权(数据将在请求头中进行传输) 参数结构: \"Authorization: Bearer {token}\"", // 描述
                        Name = "Authorization", // 授权名称
                        In = ParameterLocation.Header, // 授权位置,放在头信息进行传值
                        Type = SecuritySchemeType.ApiKey, // 授权类型
                        BearerFormat = "JWT", // 格式是JWT
                        Scheme = "Bearer"
                    });
                    // 添加安全要求
                    option.AddSecurityRequirement(new OpenApiSecurityRequirement()
                    {
                        {
                            new OpenApiSecurityScheme
                            {
                                Reference = new OpenApiReference()
                                {
                                    Id = "Bearer", // 必须和上面一致
                                    Type = ReferenceType.SecurityScheme
                                }
                            },
                            new string[] { }
                        }
                    });
                }
                #endregion
            });
        }

        public static void UseSwaggerExtension(this WebApplication app)
        {
            app.UseSwagger();
            app.UseSwaggerUI(option => {
                foreach (FieldInfo filed in typeof(ApiVersionInfo).GetFields())
                {
                    option.SwaggerEndpoint($"/swagger/{filed.Name}/swagger.json", filed.Name);
                }
            });
        }
    }
}

这里还需要在类库中安装一下主程序当中包,这里注意意义名称和版本号:

因为this修饰静态类中的静态方法,上面创建的两个方法都是静态类中的静态方法同时第一个参数还用this进行修饰,这种扩展方法可以把传参提到前面当成实例方法来进行调用,接下来我们就在入口文件中调用这两个方法:

最后我们重新运行项目,如下可以看到我们的Swagger也可以被重新运行:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2261341.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零基础开始学习鸿蒙开发-基础页面的设计

目录 1.样例图 2.逐项分析 2.1 头顶布局分析:首先我们要把第一行的图标绘制出来,一个左一个右,很明显,需要放在一个Row容器中,具体代码如下: 2.2 和头像同一行的布局,需要注意的是&#xff0c…

vscode借助插件调试OpenFoam的正确的.vscode配置文件

正确的备份文件位置: /home/jie/桌面/理解openfoam/正确的调试爆轰单进程案例/mydebugblastFoam 调试爆轰案例流体 并且工作区和用户区都是openfoam-7版本 问题:F5以debug模式启动后不停在断点 解决方法: 这里备份一下.vsode正确的配置&…

【小白包会的】使用supervisor 管理docker内多进程

使用supervisor 管理docker内多进程 一般情况下,一个docker是仅仅运行一个服务的 但是有的情况中,希望一个docker中运行多个进程,运行多个服务,也就是一个docker容器执行多个服务。 调研了一下,发现可以通过**super…

day11 性能测试(3)——Jmeter 断言+关联

【没有所谓的运气🍬,只有绝对的努力✊】 目录 1、复习 2、查看结果树 多个http请求原因分析 3、作业 4、Jmeter断言 4.1 响应断言 4.1.1 案例 4.1.2 小结 4.2 json断言 4.2.1 案例 4.2.2 小结 4.3 断言持续时间 4.3.1 案例 4.3.2 小结 4.…

热更新解决方案3 —— xLua

概述 xLua框架导入和AB包相关准备 xLua导入 其它的导入 C#调用Lua 1.Lua解析器 using System.Collections; using System.Collections.Generic; using UnityEngine; //引用命名空间 using XLua;public class Lesson1_LuaEnv : MonoBehaviour {// Start is called before the fi…

Rk3588 FFmpeg 拉流 RTSP, 硬解码转RGB

RK3588 ,基于FFmpeg, 拉取RTSP,使用 h264_rkmpp 实现硬解码. ⚡️ RK3588 编译ffmpeg参考: Ubuntu x64 架构, 交叉编译aarch64 FFmpeg mpp Code RTSPvoid hardwave_init(AVCo

谷粒商城—分布式高级①.md

1. ELASTICSEARCH 1、安装elastic search dokcer中安装elastic search (1)下载ealastic search和kibana docker pull elasticsearch:7.6.2 docker pull kibana:7.6.2(2)配置 mkdir -p /mydata/elasticsearch/config mkdir -p /mydata/elasticsearch/data echo "h…

OpenCV圆形标定板检测算法findGrid原理详解

OpenCV的findGrid函数检测圆形标定板的流程如下: class CirclesGridClusterFinder {CirclesGridClusterFinder(const CirclesGridClusterFinder&); public:CirclesGridClusterFinder

30. Three.js案例-绘制并渲染圆弧

30. Three.js案例-绘制并渲染圆弧 实现效果 知识点 WebGLRenderer WebGLRenderer 是 Three.js 中用于渲染 3D 场景的核心类。它利用 WebGL 技术在浏览器中渲染 3D 图形。 构造器 new THREE.WebGLRenderer(parameters) 参数类型描述parametersObject可选参数对象&#xff…

STM32F407ZGT6-UCOSIII笔记4:时间片轮转调度

本文学习与程序编写基于 正点原子的 STM32F1 UCOS开发手册 编写熟悉一下 UCOSIII系统的 时间片轮转调度 文章提供测试代码讲解、完整工程下载、测试效果图 目录 解决上文的卡系统问题: 使能时间片轮转调度: 任务初始化定义更改: 文件结构…

谭浩强C++课后练习(更新中)

基于过程的程序设计 第1章 C的初步知识 1. 请根据你的了解,叙述C的特点。C对C有哪些发展? 2. 一个 C程序是由哪几部分构成的?其中的每一部分起什么作用? 3. 从接到一个任务到得到最终结果,一般要经过几个步骤? 4. 请说明编辑、编译、连接的作用…

单元测试知识总结

我们希望每段代码都是自测试的,每次改动之后,都能自动发现对现有功能的影响。 1 测试要求 在对软件单元进行动态测试之前,应对软件单元的源代码进行静态测试; 应建立测试软件单元的环境,如数据准备、桩模块、模拟器…

前后端跨域问题(CROS)

前端 在src中创建util文件,写request.js文件: request.js代码如下: import axios from axios import { ElMessage } from element-plus;const request axios.create({// baseURL: /api, // 注意!! 这里是全局统一加…

【数据结构——查找】顺序查找(头歌实践教学平台习题)【合集】

目录😋 任务描述 相关知识 测试说明 我的通关代码: 测试结果: 任务描述 本关任务:实现顺序查找的算法。 相关知识 为了完成本关任务,你需要掌握:1.根据输入数据建立顺序表,2.顺序表的输出,…

Android 车载虚拟化底层技术-Kernel 5.15 -Android13(multi-cards)技术实现

系列文章请扫点击如下链接! Android Display Graphics系列文章-汇总 本文主要包括部分: 一、Android13的Kernel 5.15版本 1.1 Kernel 5.15 情况说明 1.2 前置条件 二、QCM61*5 plane配置 2.1 multi-card配置 2.2 移植msm-lease 2.3 配置信息确认…

【FFmpeg】FFmpeg 内存结构 ⑥ ( 搭建开发环境 | AVPacket 创建与释放代码分析 | AVPacket 内存使用注意事项 )

文章目录 一、搭建开发环境1、开发环境搭建参考2、项目搭建 二、AVPacket 创建与释放代码分析1、AVPacket 创建与释放代码2、Qt 单步调试方法3、单步调试 - 分析 AVPacket 创建与销毁代码 三、AVPacket 内存使用注意事项1、谨慎使用 av_init_packet 函数2、av_init_packet 函数…

C# DLT645 97/07数据采集工具

电表模拟器 97协议测试 07协议测试 private void btnSend_Click(object sender, EventArgs e) {string addr txtAddr.Text.Trim();string data txtDataFlg.Text.Trim();byte control 0x01;switch (cmbControl.SelectedIndex){case 0: control (byte)0x01; break;// 97协议c…

颜色代码表: 一站式配色方案设计工具集网站

大家好,我是一名设计师,同时也是一名开发者。平时的工作中,相信很多设计师和我一样经常遇到一个问题:设计配色方案时,工具太分散了。寻找颜色搭配灵感需要去一个网站,颜色代码转换要开另一个,检…

Android显示系统(13)- 向SurfaceFlinger提交Buffer

Android显示系统(01)- 架构分析 Android显示系统(02)- OpenGL ES - 概述 Android显示系统(03)- OpenGL ES - GLSurfaceView的使用 Android显示系统(04)- OpenGL ES - Shader绘制三角…

WebSocket 与 Server-Sent Events (SSE) 的对比与应用

目录 ✨WebSocket:全双工通信的利器📌什么是 WebSocket?📌WebSocket 的特点📌WebSocket 的优点📌WebSocket 的缺点📌WebSocket 的适用场景 ✨Server-Sent Events (SSE):单向推送的轻…