一、概述
刚参加工作时,写个API接口,还要写API文档,再使用PostMan测试接口,写文档的时间比写接口还要折腾。后来接触Swagger,API文档的工作得到了很大的改善,不但可以自动构建交互式API说明文档,还能直接调试API接口。今天记录下Core项目下使用Swagger,最新版的Swagger已经完美支持Open Api规范及JWT Token授权访问等。使用Swagger的好处总结如下:
- 使用 Swagger 生成精美的API接口文档
- 使用 Swagger 调试JWT授权接口
- 使用 Swagger 生成各个类库中视图模型的描述
二、配置Swagger服务
1、引用Nuget包
新建一个.NET Core 3.1 Web Api 项目,打开Nuget安装管理器,搜索Swashbuckle.AspNetCore,安装即可
2、配置服务
我们打开Startup.cs文件,来对Swagger配置进行一些必要的配置,在ConfigureServices方法我们添加一下Swagger配置:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Core.Api", Version = "v1" });
});
}
然后我们在Configure方法里添加swagger中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Core.Api v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
这样swagger基本配置就完成了,看下效果
3、忽略注释警告
F5运行项目后发现有很多警告:
原因是是swagger把一些 action 方法都通过xml文件配置了,如果没有加入相应的注释就会警告。如果不想每一个方法都加注释,可以如下配置:选择项目,右键属性,选择生成菜单,加入;1591
4、为接口添加注释
右键项目名称=>属性=>生成,勾选“输出”下面的“xml文档文件”,系统会默认生成一个xml。
此时项目中会生成一个 Core.Api.xml文件,修改该文件属性,选择较新则复制。然后修改下startup.cs中的ConfigureServices方法:
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Core.Api", Version = "v1" }); // 为 Swagger JSON and UI设置xml文档注释路径 //获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径) var basePath = AppContext.BaseDirectory; var xmls = Directory.GetFiles(basePath, "*.xml"); foreach (var aXml in xmls) { c.IncludeXmlComments(aXml); } }); }
然后action方法上加入注释:
/// <summary> /// 获取数据 /// </summary> /// <returns></returns> [HttpGet] public IEnumerable<WeatherForecast> Get() { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }) .ToArray(); }
看下效果:
5、为Model 添加注释
新建一个model,加入字段注释
public class StudentModel
{
/// <summary>
/// 标识
/// </summary>
public int ID { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
}
为model所在的项目也要配置xml,类似于上述第三步
//注入model 的xml
var xmlModelPath = Path.Combine(basePath, "xx.Model.xml");//这个就是Model层的xml文件名 c.IncludeXmlComments(xmlModelPath);
控制器中引用:
/// <summary>
/// 插入学生信息
/// </summary>
/// <param name="studentModel">model实体类参数</param>
/// <returns></returns>
[HttpPost]
public bool Insert([FromQuery] StudentModel studentModel)
{
return true;
}
效果如下:
6、隐藏接口
如果不想显示某些接口,直接在controller 上,或者action 上,增加特性可隐藏接口
[ApiExplorerSettings(IgnoreApi = true)]
7、Swagger启用API文档的JWT授权
目前很多网站都使用了JWT(JSON WEB TOKEN)来作为账户系统的认证授权,JWT以它的简单、高效、分布式优势很快成为了网站的流行验证方式。接下来我们为Swagger添加JWT授权认证,依旧打开Startup.cs文件,修改上面ConfigureServices方法中的代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Core.Api", Version = "v1" });
#region 加载xml
// 为 Swagger JSON and UI设置xml文档注释路径
//获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)
var basePath = AppContext.BaseDirectory;
var xmls = Directory.GetFiles(basePath, "*.xml");
foreach (var aXml in xmls)
{
c.IncludeXmlComments(aXml);
}
#endregion
#region jwt认证
// 开启加权小锁
c.OperationFilter<AddResponseHeadersFilter>();
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
// 在header中添加token,传递到后台
c.OperationFilter<SecurityRequirementsOperationFilter>();
// Jwt Bearer 认证
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Name = "Authorization",//jwt默认的参数名称
In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
Type = SecuritySchemeType.ApiKey,
Description = "Authorization:Bearer {your JWT token},注意两者之间是一个空格",
});
#endregion
});
}
预览一下授权设置,发现右侧多了一个Authorize绿色的带锁按钮,这个按钮点开后就可以设置我们的JWT Token信息了,格式是:Bearer 你的Token字符串,注意Bearer于Token之间有个空格。设置好Token后,你请求任意的API接口时,Swagger会自动附带Token到请求的Header中。
既然swagger中支持了jwt认证,那么我们在startup.cs中启用jwt认证:如下
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); #region 开启jwt认证 var symmetricKeyAsBase64 = "!@#123"; var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); var signingKey = new SymmetricSecurityKey(keyByteArray); services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { o.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = signingKey, ValidateIssuer = true, ValidIssuer = "asd",//发行人 ValidateAudience = true, ValidAudience = "fdf",//订阅人 ValidateLifetime = true, ClockSkew = TimeSpan.Zero,//这个是缓冲过期时间,也就是说,即使我们配置了过期时间,这里也要考虑进去,过期时间+缓冲 RequireExpirationTime = true, }; }); #endregion #region 配置swagger文档 services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Core.Api", Version = "v1" }); #region 加载xml // 为 Swagger JSON and UI设置xml文档注释路径 //获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径) var basePath = AppContext.BaseDirectory; var xmls = Directory.GetFiles(basePath, "*.xml"); foreach (var aXml in xmls) { c.IncludeXmlComments(aXml); } #endregion #region jwt认证 // 开启加权小锁 c.OperationFilter<AddResponseHeadersFilter>(); c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>(); // 在header中添加token,传递到后台 c.OperationFilter<SecurityRequirementsOperationFilter>(); // Jwt Bearer 认证 c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Name = "Authorization",//jwt默认的参数名称 In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey, Description = "Authorization:Bearer {your JWT token},注意两者之间是一个空格", }); #endregion }); #endregion }
更详细关于jwt认证的这里就不细讲了
8、默认直接访问swagger
有时候打开webapi项目,希望直接打开swagger文档,有两种方法:
- 方法一:设置launchSettings.json文件中的launchUrl属性,指定为swagger,如下:
- 方法二我们可以通过RoutePrefix 属性设置。
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Core.Api v1"); c.RoutePrefix = ""; //路径配置,设置为空,表示直接在根域名访问swagger文件 });
建议使用方法二。
三、Swagger异常汇总
1、问题一
如果出现如上图那样的错误,请打开swagger/v1/swagger.json查看具体原因。 常见的原因是action上没有加入HTTP请求协议,比如[HttpPost]
2、问题二
这是因为接口json文档定义和调用不是一个,请仔细对比下定义和调用的swagger名称是否一致。比如定义的时候名称为“v1”:
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Core.Api", Version = "v1" });
调用的时候也要保证一致:
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Core.Api v1"));
3、问题三
上图错误是路由重载导致的,请确保不要存在多个一样的路由。