基于.NetCore开发博客项目 StarBlog - (26) 集成Swagger接口文档
前言
这是StarBlog系列在2023年的第一篇更新~
在之前的文章里,我们已经完成了部分接口的开发,接下来需要使用 curl、Postman 这类工具对这些接口进行测试,但接口一多,每次测试都要一个个填入地址和对应参数会比较麻烦…
我们需要一种直观的方式来汇总项目里的所有接口,并且如果能直接在里面调试接口,那就更好了。
Swagger:诶嘿,说的不就是我吗?
Swagger介绍
来一段官网的介绍
Simplify API development for users, teams, and enterprises with the Swagger open source and professional toolset.
翻译:Swagger 是开源和专业的工具集,可以简化用户、团队和企业的 API 开发。
一般来说,swagger用起来有两部分,一个是 OpenAPI 一个是 SwaggerUI
在Swagger官网上,OpenAPI 介绍得天花乱坠
The OpenAPI Specification, formerly known as the Swagger Specification, is the world’s standard for defining RESTful interfaces. The OAS enables developers to design a technology-agnostic API interface that forms the basis of their API development and consumption.
翻译:OpenAPI 规范,以前称为 Swagger 规范,是定义 RESTful 接口的世界标准。 OAS 使开发人员能够设计一个与技术无关的 API 接口,该接口构成了他们 API 开发和使用的基础。
简单说 OpenAPI 是个标准,需要每种语言和框架自行实现一个工具,用来把项目里的接口都整合起来,生成 swagger.json 文件
然后 SwaggerUI 就是个网页,读取这个 swagger.json 就可以把所有接口以及参数显示出来,还可以很方便调试,效果如图。

Swashbuckle.AspNetCore
前面说到每种框架都要自己实现一个工具来生成 swagger.json ,这个 Swashbuckle.AspNetCore 就是 .NetCore 平台的实现,用就完事了。
项目主页: https://github.com/domaindrivendev/Swashbuckle.AspNetCore
Tips:如果是创建 WebApi 项目,代码模板里面默认就有 Swagger 了,不用手动添加。
StarBlog项目一开始是使用MVC模板,所以没有自带Swagger,需要手动添加。
直接使用nuget添加 Swashbuckle.AspNetCore 这个包就完事了。
这个包功能很多,内置了 SwaggerUI 这个官方界面,还有一个 ReDoc 的纯静态接口文档网页(这个 ReDoc 只能看接口不能调试)。
初步使用
为了保证 Program.cs 代码整洁,我们在 StarBlog.Web/Extensions 里面创建 ConfigureSwagger 类
public static class ConfigureSwagger {
public static void AddSwagger(this IServiceCollection services) {
services.AddSwaggerGen(options => {
options.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "APIs"});
// 在接口文档上显示 XML 注释
var filePath = Path.Combine(System.AppContext.BaseDirectory, $"{typeof(Program).Assembly.GetName().Name}.xml");
options.IncludeXmlComments(filePath, true);
});
}
public static void UseSwaggerPkg(this IApplicationBuilder app) {
app.UseSwagger();
app.UseSwaggerUI(options => {
options.RoutePrefix = "api-docs/swagger";
options.SwaggerEndpoint("/swagger/v1/swagger.json", "APIs");
});
app.UseReDoc(options => {
options.RoutePrefix = "api-docs/redoc";
options.SpecUrl = "/swagger/v1/swagger.json";
});
}
}
上面代码可以看到有三步
AddSwaggerGen- 对应前文说的生成swagger.jsonUseSwagger- 让浏览器可以访问到/swagger/v1/swagger.json这类路径UseSwaggerUI- 提供 SwaggerUI 的网页访问
然后回到 Program.cs 里面,分别注册服务和添加中间件就好了。
// 注册服务
builder.Services.AddSwagger();
// 添加中间件
app.UseSwaggerPkg();
现在启动项目,访问 http://[本地地址]/api-docs/swagger 就能看到接口文档了
效果大概这样

扩展:关于XML注释
C# 的代码注释可以导出XML,然后显示在 swagger 文档上
注意需要手动在 .csproj 项目配置里面开启,才会输出XML文档
<!-- 输出XML -->
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
但是开启XML之后,IDE很蠢的要求我们所有public成员都写上注释,很烦,加上 <NoWarn>$(NoWarn);1591</NoWarn> 这行就可以关掉这个警告。
在 Swagger 里加载XML文档,既可以用本文前面写的方式
var filePath = Path.Combine(System.AppContext.BaseDirectory, $"{typeof(Program).Assembly.GetName().Name}.xml");
options.IncludeXmlComments(filePath, true);
还可以用第二种,加载目录里的全部XML
var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
foreach (var file in xmlFiles) {
options.IncludeXmlComments(file, true);
}
具体用哪种,都行吧,看心情~
扩展:关于 AddEndpointsApiExplorer
在 AddSwagger 扩展方法这里可能有同学会有疑问
为啥创建 .Net6 项目后默认是这两行代码
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
而我这里只有一行代码
services.AddSwaggerGen();
先说结论:AddEndpointsApiExplorer 是为了支持 Minimal Api 的。
因为 StarBlog 项目使用的是MVC模板,在 Program.cs 的最开始可以看到这行代码,添加控制器和视图
builder.Services.AddControllersWithViews();
翻一下这个框架的源码,可以看到这个方法的套娃是这样的
AddControllersWithViews() -> AddControllersWithViewsCore() -> AddControllersCore()
而在 AddControllersCore 里面,又调用了 AddApiExplorer
private static IMvcCoreBuilder AddControllersCore(IServiceCollection services) {
// This method excludes all of the view-related services by default.
var builder = services
.AddMvcCore()
.AddApiExplorer()
.AddAuthorization()
.AddCors()
.AddDataAnnotations()
.AddFormatterMappings();
if (MetadataUpdater.IsSupported) {
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IActionDescriptorChangeProvider, HotReloadService>());
}
return builder;
}
就是说正常的项目已经有 ApiExplorer 这个东西了,但是 Minimal Api 项目没有,所以本项目不需要 builder.Services.AddEndpointsApiExplorer(); 这行代码。
详情可以阅读参考资料的第一个链接。
接口分组
接口文档有了,但项目里接口太多了,几十个接口全挤在一个页面上,找都找得眼花了
这时候可以给接口分个组
先来给 StarBlog 项目里面的接口分个类,根据不同用途,大致分成这五类:
- admin - 管理员相关接口
- common - 通用公共接口
- auth - 授权接口
- blog - 博客管理接口
- test - 测试接口
还是在上面那个 ConfigureSwagger.cs 文件
修改 AddSwagger 方法,把这几个分组添加进去
services.AddSwaggerGen(options => {
options.SwaggerDoc("admin", new OpenApiInfo {
Version = "v1",
Title = "Admin APIs",
Description = "管理员相关接口"
});
options.SwaggerDoc("common", new OpenApiInfo {
Version = "v1",
Title = "Common APIs",
Description = "通用公共接口"
});
options.SwaggerDoc("auth", new OpenApiInfo {
Version = "v1",
Title = "Auth APIs",
Description = "授权接口"
});
options.SwaggerDoc("blog", new OpenApiInfo {
Version = "v1",
Title = "Blog APIs",
Description = "博客管理接口"
});
options.SwaggerDoc("test", new OpenApiInfo {
Version = "v1",
Title = "Test APIs",
Description = "测试接口"
});
});
这样就会生成五个 swagger.json 文件,路径分别是
/swagger/admin/swagger.json/swagger/common/swagger.json/swagger/auth/swagger.json/swagger/blog/swagger.json/swagger/test/swagger.json
所以下面的 UseSwaggerPkg 方法也要对应修改
public static void UseSwaggerPkg(this IApplicationBuilder app) {
app.UseSwagger();
app.UseSwaggerUI(options => {
options.RoutePrefix = "api-docs/swagger";
options.SwaggerEndpoint("/swagger/admin/swagger.json", "Admin");
options.SwaggerEndpoint("/swagger/blog/swagger.json", "Blog");
options.SwaggerEndpoint("/swagger/auth/swagger.json", "Auth");
options.SwaggerEndpoint("/swagger/common/swagger.json", "Common");
options.SwaggerEndpoint("/swagger/test/swagger.json", "Test");
});
}
接下来,要让 Swagger 知道每个接口都是属于哪个分组的。
具体方法是在 Controller 上添加 ApiExplorerSettings 特性。
比如 BlogController 是属于 blog 分组,在 class 定义前面添加一行代码
[ApiExplorerSettings(GroupName = "blog")]
public class BlogController : ControllerBase {
// ...
}
其他的 Controller 也是类似的操作,具体分组跟 StarBlog.Web/Apis 下的目录结构一样,这里就不赘述了。
实现效果
做完之后,打开 swagger 接口文档页面
可以看到右上角可以选择接口分组了

搞定。
优化分组
前文对于 Swagger 分组的实现其实是一种硬编码,不同分组的 Controller 上面需要加上 [ApiExplorerSettings(GroupName = "blog")] 特性,分组名全靠复制粘贴,在项目比较小的情况下还好,如果分组多起来了,有几百个接口的时候,估计人就麻了吧
Q:“你刚才干嘛不早说”
A:“循序渐进嘛”
A:“StarBlog项目也是最近才换到新版分组的”
在 StarBlog.Web/Models 里添加个新的类 SwaggerGroup
public class SwaggerGroup {
/// <summary>
/// 组名称(同时用于做URL前缀)
/// </summary>
public string Name { get; set; }
public string? Title { get; set; }
public string? Description { get; set; }
public SwaggerGroup(string name, string? title = null, string? description = null) {
Name = name;
Title = title;
Description = description;
}
/// <summary>
/// 生成 <see cref="Microsoft.OpenApi.Models.OpenApiInfo"/>
/// </summary>
public OpenApiInfo ToOpenApiInfo(string version = "1.0") {
var item = new OpenApiInfo();
Title ??= Name;
Description ??= Name;
return new OpenApiInfo { Title = Title, Description = Description, Version = version };
}
}
然后改造一下 StarBlog.Web/Extensions/ConfigureSwagger.cs
在这个文件里面添加个新的类,这样就不会硬编码了
public static class ApiGroups {
public const string Admin = "admin";
public const string Auth = "auth";
public const string Common = "common";
public const string Blog = "blog";
public const string Test = "test";
}
在 ConfigureSwagger 里添加一些代码,创建 SwaggerGroup 列表
public static class ConfigureSwagger {
public static readonly List<SwaggerGroup> Groups = new() {
new SwaggerGroup(ApiGroups.Admin, "Admin APIs", "管理员相关接口"),
new SwaggerGroup(ApiGroups.Auth, "Auth APIs", "授权接口"),
new SwaggerGroup(ApiGroups.Common, "Common APIs", "通用公共接口"),
new SwaggerGroup(ApiGroups.Blog, "Blog APIs", "博客管理接口"),
new SwaggerGroup(ApiGroups.Test, "Test APIs", "测试接口")
};
}
然后把后面的 AddSwagger 方法改成这样,那一坨东西,现在一行代码就代替了
public static void AddSwagger(this IServiceCollection services) {
services.AddSwaggerGen(options => {
Groups.ForEach(group => options.SwaggerDoc(group.Name, group.ToOpenApiInfo()));
// XML注释
var filePath = Path.Combine(AppContext.BaseDirectory, $"{typeof(Program).Assembly.GetName().Name}.xml");
options.IncludeXmlComments(filePath, true);
});
}
接着是 UseSwaggerPkg 方法,简单
public static void UseSwaggerPkg(this IApplicationBuilder app) {
app.UseSwagger();
app.UseSwaggerUI(opt => {
opt.RoutePrefix = "api-docs/swagger";
// 分组
Groups.ForEach(group => opt.SwaggerEndpoint($"/swagger/{group.Name}/swagger.json", group.Name));
});
}
Controller里面也对应修改成这样
[ApiExplorerSettings(GroupName = ApiGroups.Blog)]
public class BlogController : ControllerBase {
}
完美
小结
“Swagger之大,一锅炖不下”
关于Swagger还有其他的用法,但需要一些前置知识,因此本文不会把StarBlog项目中关于Swagger的部分全部介绍完
等把相关的前置知识写完,再来完善对应的用法~
这也跟StarBlog的开发过程是吻合的
参考资料
系列文章
- 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客?
- 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目
- 基于.NetCore开发博客项目 StarBlog - (3) 模型设计
- 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入
- 基于.NetCore开发博客项目 StarBlog - (5) 开始搭建Web项目
- 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表
- 基于.NetCore开发博客项目 StarBlog - (7) 页面开发之文章详情页面
- 基于.NetCore开发博客项目 StarBlog - (8) 分类层级结构展示
- 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入
- 基于.NetCore开发博客项目 StarBlog - (10) 图片瀑布流
- 基于.NetCore开发博客项目 StarBlog - (11) 实现访问统计
- 基于.NetCore开发博客项目 StarBlog - (12) Razor页面动态编译
- 基于.NetCore开发博客项目 StarBlog - (13) 加入友情链接功能
- 基于.NetCore开发博客项目 StarBlog - (14) 实现主题切换功能
- 基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片
- 基于.NetCore开发博客项目 StarBlog - (16) 一些新功能 (监控/统计/配置/初始化)
- 基于.NetCore开发博客项目 StarBlog - (17) 自动下载文章里的外部图片
- 基于.NetCore开发博客项目 StarBlog - (18) 实现本地Typora文章打包上传
- 基于.NetCore开发博客项目 StarBlog - (19) Markdown渲染方案探索
- 基于.NetCore开发博客项目 StarBlog - (20) 图片显示优化
- 基于.NetCore开发博客项目 StarBlog - (21) 开始开发RESTFul接口
- 基于.NetCore开发博客项目 StarBlog - (22) 开发博客文章相关接口
- 基于.NetCore开发博客项目 StarBlog - (23) 文章列表接口分页、过滤、搜索、排序
- 基于.NetCore开发博客项目 StarBlog - (24) 统一接口数据返回格式
- 基于.NetCore开发博客项目 StarBlog - (25) 图片接口与文件上传
- 基于.NetCore开发博客项目 StarBlog - (26) 集成Swagger接口文档
基于.NetCore开发博客项目 StarBlog - (26) 集成Swagger接口文档的更多相关文章
- 基于.NetCore开发博客项目 StarBlog - (16) 一些新功能 (监控/统计/配置/初始化)
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 ... 基于. ...
- 基于.NetCore开发博客项目 StarBlog - (3) 模型设计
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (5) 开始搭建Web项目
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (7) 页面开发之文章详情页面
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (8) 分类层级结构展示
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (10) 图片瀑布流
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
随机推荐
- 我的Vue之旅 09 数据数据库表的存储与获取实现 Mysql + Golang
第四期 · 将部分数据存储至Mysql,使用axios通过golang搭建的http服务器获取数据. 新建数据库 DROP DATABASE VUE; create database if not e ...
- Django系列---开发一
参考 杜赛: https://www.dusaiphoto.com/article/2/ 官方文档: https://docs.djangoproject.com/en/3.2/ 开发环境 # 基本 ...
- Linux操作系统,笔录!
1.Linux 1.1.Linux介绍: Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX ...
- springboot滚动分页展示列表(类似layui瀑布流效果)
背景: 公司项目要求获取用户关联的好友列表,要求分页查询,十条数据一页,滚动页面是点击加载更多,显示下一页列表. 示例图: 实现: 本项目采用的前端模板是freemaker,主要前端页面代码(没有 ...
- Vue3组件间传值
12种方式 1. 父组件 ./father.vue 点击查看代码 <template> <h1>father:</h1> <h3>子组件传过来的:{{ ...
- 6、将两个字符串连接起来,不使用strcat函数
/* 将两个字符串连接起来,不使用strcat函数 */ #include <stdio.h> #include <stdlib.h> void strCat(char *pS ...
- 【云原生 · Kubernetes】Kubernetes 编排部署GPMall(一)
1.规划节点 IP 主机名 节点 10.24.2.156 master Kubernetes master 节点 10.24.2.157 node Kubernetes worker 节点 2.基础准 ...
- Kubernetes_从云原生到kubernetes
一.前言 二.kubernetes和云原生 Cloud Native 直接翻译为云原生,云原生官网:https://www.cncf.io/ CNCF,表示 Cloud Native Computin ...
- 模块/os/sys/json
目录 内容概要 1.os模块 2.sys模块 3.json模块/实战 内容概要 os模块 sys模块 json模块/实战 1.os模块 # os模块主要是与我们的操作系统打交道 1.创建文件夹(目录) ...
- 6 STL-vector
重新系统学习c++语言,并将学习过程中的知识在这里抄录.总结.沉淀.同时希望对刷到的朋友有所帮助,一起加油哦! 生命就像一朵花,要拼尽全力绽放!死磕自个儿,身心愉悦! 写在前面,本篇章主要介绍S ...