本文使用特性來描述接口而不是xml文件,使用特性可自定義接口在swaggerUI上的描述
安裝nuget包:Swashbuckle.AspNetCore.SwaggerUI
和
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; namespace swaggerweb { public class Startup { private readonly string swaggerDocName = "weather"; public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddSwaggerGen(opt => { opt.SwaggerDoc(swaggerDocName, new OpenApiInfo() { Version = "v1", Title = "WeatherForecast", Description = "天氣預報" }); // 使用annotation來描述接口,不依賴XML文件 opt.EnableAnnotations(); // 下面兩句,將swagger文檔中controller名使用GroupName替換 // 在Swagger中,一個Tag可以看作是一個API分組 opt.DocInclusionPredicate((_, apiDescription) => string.IsNullOrWhiteSpace(apiDescription.GroupName) == false); opt.SwaggerGeneratorOptions.TagsSelector = (apiDescription) => new[] { apiDescription.GroupName }; }); services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseSwagger(opt => { // 相對路徑加載swagger文檔 //opt.RouteTemplate = "swagger/{documentName}"; }) .UseSwaggerUI(opt => { opt.SwaggerEndpoint($"{swaggerDocName}/swagger.json", "天氣預報API文檔"); }); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); // 也可以在這里配置swagger文檔路徑 //endpoints.MapSwagger(); }); } } }
Controller和Action上使用特性:ApiExplorerSettings
和SwaggerOperation
:
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Swashbuckle.AspNetCore.Annotations; using System; using System.Collections.Generic; using System.Linq; namespace swaggerweb.Controllers { [ApiExplorerSettings(GroupName = "天氣預報")] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet] [SwaggerOperation(Summary = "獲取天氣預報信息")] 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(); } } }
效果圖:
2020-07-28 補充
1. 默認折疊swagger 文檔
當接口比較多時,展開Tag看起來比較費力,這里折疊下
public void Configure(IApplicationBuilder app, IHostEnvironment env) { app.UseSwagger().UseSwaggerUI(opt => { // 折疊所有的Tag opt.DocExpansion(DocExpansion.None); // 隱藏API中定義的model opt.DefaultModelsExpandDepth(-1); }); }
2. 添加Authorization請求頭
有些接口需要認證/授權,這里針對ASP.NET Core中在Controller上標記Authorize特性的情況,使用swagger中的自定義Filter來實現在swagger界面上發起請求時傳遞授權token
public void ConfigureServices(IServiceCollection services) { services.AddSwaggerGen(opt => { opt.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Scheme = "bearer", BearerFormat = "JWT", Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http }); opt.OperationFilter<AuthenticationOperationFilter>(); }); }
自定義過濾器:
public class AuthenticationOperationFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { var actionScopes = context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Select(attr => attr.TypeId.ToString()).Distinct(); var controllerScopes = context.MethodInfo.DeclaringType!.GetCustomAttributes(true) .Union(context.MethodInfo.GetCustomAttributes(true)) .OfType<AuthorizeAttribute>() .Select(attr => attr.TypeId.ToString()); var requiredScopes = actionScopes.Union(controllerScopes).Distinct().ToArray(); if (requiredScopes.Any()) { operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" }); operation.Responses.Add("419", new OpenApiResponse { Description = "AuthenticationTimeout" }); operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" }); var oAuthScheme = new OpenApiSecurityScheme { Scheme = "Bearer", Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }; operation.Security = new List<OpenApiSecurityRequirement> { new OpenApiSecurityRequirement { [ oAuthScheme ] = new List<string>() } }; } } }
swagger界面上,每個API及swagger頂部均會出現小鎖,點擊小鎖可以輸入token:
3. 序列化問題
發現API中若定義了IDictionary<,>類型的字段,swagger默認的序列化方式會出錯,這里使用Newtonsoft來序列化。需要安裝nuget包:Swashbuckle.AspNetCore.Newtonsoft:
public void ConfigureServices(IServiceCollection services) { services.AddSwaggerGen().AddSwaggerGenNewtonsoftSupport(); }