如何设置 Swashbuckle 与 Microsoft.AspNetCore.Mvc.Versioning
How to set up Swashbuckle vs Microsoft.AspNetCore.Mvc.Versioning
我们有 asp.net 核心 webapi。我们添加了 Microsoft.AspNetCore.Mvc.Versioning
和 Swashbuckle
以拥有 swagger UI。
我们将控制器指定为:
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ContactController : Controller
{
当我们运行 swagger ui 我们在路由中获取版本作为参数:
如何设置路由的默认 "v1"?
如果版本 2 出现,如何支持两个版本的 swagger ui?
目前 Swashbuckle 和 Microsoft.AspNetCore.Mvc.Versioning 是朋友。它运作良好。我刚刚在 VS2017 中创建了测试项目并检查了它是如何工作的。
首先包含这两个nuget包:
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
配置 Startup.cs
中的所有内容(阅读我的评论):
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Configure versions
services.AddApiVersioning(o =>
{
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
});
// Configure swagger
services.AddSwaggerGen(options =>
{
// Specify two versions
options.SwaggerDoc("v1",
new Info()
{
Version = "v1",
Title = "v1 API",
Description = "v1 API Description",
TermsOfService = "Terms of usage v1"
});
options.SwaggerDoc("v2",
new Info()
{
Version = "v2",
Title = "v2 API",
Description = "v2 API Description",
TermsOfService = "Terms of usage v2"
});
// This call remove version from parameter, without it we will have version as parameter
// for all endpoints in swagger UI
options.OperationFilter<RemoveVersionFromParameter>();
// This make replacement of v{version:apiVersion} to real version of corresponding swagger doc.
options.DocumentFilter<ReplaceVersionWithExactValueInPath>();
// This on used to exclude endpoint mapped to not specified in swagger version.
// In this particular example we exclude 'GET /api/v2/Values/otherget/three' endpoint,
// because it was mapped to v3 with attribute: MapToApiVersion("3")
options.DocInclusionPredicate((version, desc) =>
{
var versions = desc.ControllerAttributes()
.OfType<ApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
var maps = desc.ActionAttributes()
.OfType<MapToApiVersionAttribute>()
.SelectMany(attr => attr.Versions)
.ToArray();
return versions.Any(v => $"v{v.ToString()}" == version) && (maps.Length == 0 || maps.Any(v => $"v{v.ToString()}" == version));
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"/swagger/v2/swagger.json", $"v2");
c.SwaggerEndpoint($"/swagger/v1/swagger.json", $"v1");
});
app.UseMvc();
}
有两个 class 可以解决问题:
public class RemoveVersionFromParameter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var versionParameter = operation.Parameters.Single(p => p.Name == "version");
operation.Parameters.Remove(versionParameter);
}
}
public class ReplaceVersionWithExactValueInPath : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
swaggerDoc.Paths = swaggerDoc.Paths
.ToDictionary(
path => path.Key.Replace("v{version}", swaggerDoc.Info.Version),
path => path.Value
);
}
}
RemoveVersionFromParameter
从 swagger UI 中删除此文本框:
ReplaceVersionWithExactValueInPath
改变这个:
对此:
控制器 class 现在看起来如下:
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1")]
[ApiVersion("2")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
[HttpGet("otherget/one")]
[MapToApiVersion("2")]
public IEnumerable<string> Get2()
{
return new string[] { "value1", "value2" };
}
/// <summary>
/// THIS ONE WILL BE EXCLUDED FROM SWAGGER Ui, BECAUSE v3 IS NOT SPECIFIED. 'DocInclusionPredicate' MAKES THE
/// TRICK
/// </summary>
/// <returns></returns>
[HttpGet("otherget/three")]
[MapToApiVersion("3")]
public IEnumerable<string> Get3()
{
return new string[] { "value1", "value2" };
}
}
代码:https://gist.github.com/Alezis/bab8b559d0d8800c994d065db03ab53e
@Alezis 不错的方法,但如果您使用的是最新版本的 Microsoft.AspNetCore.Mvc.Versioning (2.3.0) 库,ControllerAttributes()
和 ActionAttributes()
已弃用,您可以更新 DocInclusionPredicate
如下:
options.DocInclusionPredicate((version, desc) =>
{
if (!desc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
var versions = methodInfo.DeclaringType
.GetCustomAttributes(true)
.OfType<ApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
return versions.Any(v => $"v{v.ToString()}" == version);
});
Swashbuckle.AspNetCore github 项目对我帮助很大。
我发现使用 需要 {00:00:00.0001905}
才能完成,而 运行
var versions = methodInfo.DeclaringType.GetConstructors().SelectMany(x =>
x.DeclaringType.CustomAttributes.Where(y =>
y.AttributeType == typeof(ApiVersionAttribute))
.SelectMany(z => z.ConstructorArguments.Select(i=>i.Value)));
拍了{00:00:00.0000626}
我知道我们在谈论细微差别,但仍然如此。
更新到 .net core 3 时出现以下错误:
'无法将类型 'System.Collections.Generic.Dictionary`2[System.String,Microsoft.OpenApi.Models.OpenApiPathItem]' 的对象转换为类型 'Microsoft.OpenApi.Models.OpenApiPaths'。'
通过更改代码修复此问题:
public class ReplaceVersionWithExactValueInPath : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
if (swaggerDoc == null)
throw new ArgumentNullException(nameof(swaggerDoc));
var replacements = new OpenApiPaths();
foreach (var (key, value) in swaggerDoc.Paths)
{
replacements.Add(key.Replace("{version}", swaggerDoc.Info.Version, StringComparison.InvariantCulture), value);
}
swaggerDoc.Paths = replacements;
}
}
如果使用 .Net Core 3,基本上我采用了@Alezis 的解决方案并将其更新为与 .Net Core 3 一起使用:
public void ConfigureServices(IServiceCollection services)
{
....
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo() { Title = "My API", Version = "v1" });
options.OperationFilter<RemoveVersionFromParameter>();
options.DocumentFilter<ReplaceVersionWithExactValueInPath>();
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
...
}
public class RemoveVersionFromParameter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var versionParameter = operation.Parameters.Single(p => p.Name == "version");
operation.Parameters.Remove(versionParameter);
}
}
public class ReplaceVersionWithExactValueInPath : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
var paths = new OpenApiPaths();
foreach (var path in swaggerDoc.Paths)
{
paths.Add(path.Key.Replace("v{version}", swaggerDoc.Info.Version), path.Value);
}
swaggerDoc.Paths = paths;
}
}
您可以使用 Microsoft 提供的向 API 资源管理器添加版本的库,而不是调整 OpenAPI 文档。这样,在 Swashbuckle(或其他工具链)需要它之前提供版本,并允许您避免自定义代码。
Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
添加包和这段代码后,我能够正确配置版本。
services.AddVersionedApiExplorer(
options =>
{
// add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
// note: the specified format code will format the version as "'v'major[.minor][-status]"
options.GroupNameFormat = "'v'VVV";
// note: this option is only necessary when versioning by url segment. the SubstitutionFormat
// can also be used to control the format of the API version in route templates
options.SubstituteApiVersionInUrl = true;
}
);
@ArlanG 它帮助了我,谢谢。它适用于 Asp.Net Core 3.1。从我的角度来看,有一个小的澄清。如果你想获得更多类似的行为,如主要答案@Alezis 方法实现 DocInclusionPredicate() 可以是:
options.DocInclusionPredicate((version, desc) =>
{
if (!desc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
var versions = methodInfo.DeclaringType
.GetCustomAttributes(true)
.OfType<ApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
var maps = methodInfo
.GetCustomAttributes(true)
.OfType<MapToApiVersionAttribute>()
.SelectMany(attr => attr.Versions)
.ToArray();
return versions.Any(v => $"v{v.ToString()}" == version)
&& (!maps.Any() || maps.Any(v => $"v{v.ToString()}" == version));
});
在这种情况下,当您在 SwaggerUi 页面上选择一个版本时,它只会显示映射到该版本的控制器方法。
在Asp.core 2.+添加这个class:
public class ApiVersionOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var actionApiVersionModel = context.ApiDescription.ActionDescriptor?.GetApiVersion();
if (actionApiVersionModel == null)
{
return;
}
if (actionApiVersionModel.DeclaredApiVersions.Any())
{
operation.Produces = operation.Produces
.SelectMany(p => actionApiVersionModel.DeclaredApiVersions
.Select(version => $"{p};v={version.ToString()}")).ToList();
}
else
{
operation.Produces = operation.Produces
.SelectMany(p => actionApiVersionModel.ImplementedApiVersions.OrderByDescending(v => v)
.Select(version => $"{p};v={version.ToString()}")).ToList();
}
}
}
next 在 configureServices 方法中添加以下代码 startup:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "Versioned Api v1", Version = "v1" });
c.OperationFilter<ApiVersionOperationFilter>();
});
then 在 configure 方法中添加以下代码 startup:
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Versioned Api v1");
c.RoutePrefix = string.Empty;
在 Asp.core 3.+ 添加这些 classes:
public class RemoveVersionFromParameter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (!operation.Parameters.Any())
return;
var versionParameter = operation.Parameters
.FirstOrDefault(p => p.Name.ToLower() == "version");
if (versionParameter != null)
operation.Parameters.Remove(versionParameter);
}
}
public class ReplaceVersionWithExactValueInPath : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
if (swaggerDoc == null)
throw new ArgumentNullException(nameof(swaggerDoc));
var replacements = new OpenApiPaths();
foreach (var (key, value) in swaggerDoc.Paths)
{
replacements.Add(key.Replace("v{version}", swaggerDoc.Info.Version,
StringComparison.InvariantCulture), value);
}
swaggerDoc.Paths = replacements;
}
}
next 在 ConfigureServices 方法中添加以下代码 startup:
protected virtual IEnumerable<int> Versions => new[] {1};
services.AddSwaggerGen(options =>
{
Versions.ToList()
.ForEach(v =>
options.SwaggerDoc($"v{v}",
new OpenApiInfo
{
Title = $"Versioned Api:v{v}", Version = $"v{v}"
}));
options.OperationFilter<RemoveVersionFromParameter>();
options.DocumentFilter<ReplaceVersionWithExactValueInPath>();
options.RoutePrefix = string.Empty;
});
then 在 configure 方法中添加以下代码 startup:
app.UseSwagger();
app.UseSwaggerUI(options =>
{
Versions.ToList()
.ForEach(v => options.SwaggerEndpoint($"/swagger/v{v}/swagger.json", $"Versioned Api:v{v}"));
options.RoutePrefix = string.Empty;
});
我们有 asp.net 核心 webapi。我们添加了 Microsoft.AspNetCore.Mvc.Versioning
和 Swashbuckle
以拥有 swagger UI。
我们将控制器指定为:
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ContactController : Controller
{
当我们运行 swagger ui 我们在路由中获取版本作为参数:
如何设置路由的默认 "v1"? 如果版本 2 出现,如何支持两个版本的 swagger ui?
目前 Swashbuckle 和 Microsoft.AspNetCore.Mvc.Versioning 是朋友。它运作良好。我刚刚在 VS2017 中创建了测试项目并检查了它是如何工作的。
首先包含这两个nuget包:
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
配置 Startup.cs
中的所有内容(阅读我的评论):
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Configure versions
services.AddApiVersioning(o =>
{
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
});
// Configure swagger
services.AddSwaggerGen(options =>
{
// Specify two versions
options.SwaggerDoc("v1",
new Info()
{
Version = "v1",
Title = "v1 API",
Description = "v1 API Description",
TermsOfService = "Terms of usage v1"
});
options.SwaggerDoc("v2",
new Info()
{
Version = "v2",
Title = "v2 API",
Description = "v2 API Description",
TermsOfService = "Terms of usage v2"
});
// This call remove version from parameter, without it we will have version as parameter
// for all endpoints in swagger UI
options.OperationFilter<RemoveVersionFromParameter>();
// This make replacement of v{version:apiVersion} to real version of corresponding swagger doc.
options.DocumentFilter<ReplaceVersionWithExactValueInPath>();
// This on used to exclude endpoint mapped to not specified in swagger version.
// In this particular example we exclude 'GET /api/v2/Values/otherget/three' endpoint,
// because it was mapped to v3 with attribute: MapToApiVersion("3")
options.DocInclusionPredicate((version, desc) =>
{
var versions = desc.ControllerAttributes()
.OfType<ApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
var maps = desc.ActionAttributes()
.OfType<MapToApiVersionAttribute>()
.SelectMany(attr => attr.Versions)
.ToArray();
return versions.Any(v => $"v{v.ToString()}" == version) && (maps.Length == 0 || maps.Any(v => $"v{v.ToString()}" == version));
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"/swagger/v2/swagger.json", $"v2");
c.SwaggerEndpoint($"/swagger/v1/swagger.json", $"v1");
});
app.UseMvc();
}
有两个 class 可以解决问题:
public class RemoveVersionFromParameter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var versionParameter = operation.Parameters.Single(p => p.Name == "version");
operation.Parameters.Remove(versionParameter);
}
}
public class ReplaceVersionWithExactValueInPath : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
swaggerDoc.Paths = swaggerDoc.Paths
.ToDictionary(
path => path.Key.Replace("v{version}", swaggerDoc.Info.Version),
path => path.Value
);
}
}
RemoveVersionFromParameter
从 swagger UI 中删除此文本框:
ReplaceVersionWithExactValueInPath
改变这个:
对此:
控制器 class 现在看起来如下:
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1")]
[ApiVersion("2")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
[HttpGet("otherget/one")]
[MapToApiVersion("2")]
public IEnumerable<string> Get2()
{
return new string[] { "value1", "value2" };
}
/// <summary>
/// THIS ONE WILL BE EXCLUDED FROM SWAGGER Ui, BECAUSE v3 IS NOT SPECIFIED. 'DocInclusionPredicate' MAKES THE
/// TRICK
/// </summary>
/// <returns></returns>
[HttpGet("otherget/three")]
[MapToApiVersion("3")]
public IEnumerable<string> Get3()
{
return new string[] { "value1", "value2" };
}
}
代码:https://gist.github.com/Alezis/bab8b559d0d8800c994d065db03ab53e
@Alezis 不错的方法,但如果您使用的是最新版本的 Microsoft.AspNetCore.Mvc.Versioning (2.3.0) 库,ControllerAttributes()
和 ActionAttributes()
已弃用,您可以更新 DocInclusionPredicate
如下:
options.DocInclusionPredicate((version, desc) =>
{
if (!desc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
var versions = methodInfo.DeclaringType
.GetCustomAttributes(true)
.OfType<ApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
return versions.Any(v => $"v{v.ToString()}" == version);
});
Swashbuckle.AspNetCore github 项目对我帮助很大。
我发现使用 {00:00:00.0001905}
才能完成,而 运行
var versions = methodInfo.DeclaringType.GetConstructors().SelectMany(x =>
x.DeclaringType.CustomAttributes.Where(y =>
y.AttributeType == typeof(ApiVersionAttribute))
.SelectMany(z => z.ConstructorArguments.Select(i=>i.Value)));
拍了{00:00:00.0000626}
我知道我们在谈论细微差别,但仍然如此。
更新到 .net core 3 时出现以下错误:
'无法将类型 'System.Collections.Generic.Dictionary`2[System.String,Microsoft.OpenApi.Models.OpenApiPathItem]' 的对象转换为类型 'Microsoft.OpenApi.Models.OpenApiPaths'。'
通过更改代码修复此问题:
public class ReplaceVersionWithExactValueInPath : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
if (swaggerDoc == null)
throw new ArgumentNullException(nameof(swaggerDoc));
var replacements = new OpenApiPaths();
foreach (var (key, value) in swaggerDoc.Paths)
{
replacements.Add(key.Replace("{version}", swaggerDoc.Info.Version, StringComparison.InvariantCulture), value);
}
swaggerDoc.Paths = replacements;
}
}
如果使用 .Net Core 3,基本上我采用了@Alezis 的解决方案并将其更新为与 .Net Core 3 一起使用:
public void ConfigureServices(IServiceCollection services)
{
....
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo() { Title = "My API", Version = "v1" });
options.OperationFilter<RemoveVersionFromParameter>();
options.DocumentFilter<ReplaceVersionWithExactValueInPath>();
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
...
}
public class RemoveVersionFromParameter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var versionParameter = operation.Parameters.Single(p => p.Name == "version");
operation.Parameters.Remove(versionParameter);
}
}
public class ReplaceVersionWithExactValueInPath : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
var paths = new OpenApiPaths();
foreach (var path in swaggerDoc.Paths)
{
paths.Add(path.Key.Replace("v{version}", swaggerDoc.Info.Version), path.Value);
}
swaggerDoc.Paths = paths;
}
}
您可以使用 Microsoft 提供的向 API 资源管理器添加版本的库,而不是调整 OpenAPI 文档。这样,在 Swashbuckle(或其他工具链)需要它之前提供版本,并允许您避免自定义代码。
Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
添加包和这段代码后,我能够正确配置版本。
services.AddVersionedApiExplorer(
options =>
{
// add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
// note: the specified format code will format the version as "'v'major[.minor][-status]"
options.GroupNameFormat = "'v'VVV";
// note: this option is only necessary when versioning by url segment. the SubstitutionFormat
// can also be used to control the format of the API version in route templates
options.SubstituteApiVersionInUrl = true;
}
);
@ArlanG 它帮助了我,谢谢。它适用于 Asp.Net Core 3.1。从我的角度来看,有一个小的澄清。如果你想获得更多类似的行为,如主要答案@Alezis 方法实现 DocInclusionPredicate() 可以是:
options.DocInclusionPredicate((version, desc) =>
{
if (!desc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
var versions = methodInfo.DeclaringType
.GetCustomAttributes(true)
.OfType<ApiVersionAttribute>()
.SelectMany(attr => attr.Versions);
var maps = methodInfo
.GetCustomAttributes(true)
.OfType<MapToApiVersionAttribute>()
.SelectMany(attr => attr.Versions)
.ToArray();
return versions.Any(v => $"v{v.ToString()}" == version)
&& (!maps.Any() || maps.Any(v => $"v{v.ToString()}" == version));
});
在这种情况下,当您在 SwaggerUi 页面上选择一个版本时,它只会显示映射到该版本的控制器方法。
在Asp.core 2.+添加这个class:
public class ApiVersionOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var actionApiVersionModel = context.ApiDescription.ActionDescriptor?.GetApiVersion();
if (actionApiVersionModel == null)
{
return;
}
if (actionApiVersionModel.DeclaredApiVersions.Any())
{
operation.Produces = operation.Produces
.SelectMany(p => actionApiVersionModel.DeclaredApiVersions
.Select(version => $"{p};v={version.ToString()}")).ToList();
}
else
{
operation.Produces = operation.Produces
.SelectMany(p => actionApiVersionModel.ImplementedApiVersions.OrderByDescending(v => v)
.Select(version => $"{p};v={version.ToString()}")).ToList();
}
}
}
next 在 configureServices 方法中添加以下代码 startup:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "Versioned Api v1", Version = "v1" });
c.OperationFilter<ApiVersionOperationFilter>();
});
then 在 configure 方法中添加以下代码 startup:
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Versioned Api v1");
c.RoutePrefix = string.Empty;
在 Asp.core 3.+ 添加这些 classes:
public class RemoveVersionFromParameter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (!operation.Parameters.Any())
return;
var versionParameter = operation.Parameters
.FirstOrDefault(p => p.Name.ToLower() == "version");
if (versionParameter != null)
operation.Parameters.Remove(versionParameter);
}
}
public class ReplaceVersionWithExactValueInPath : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
if (swaggerDoc == null)
throw new ArgumentNullException(nameof(swaggerDoc));
var replacements = new OpenApiPaths();
foreach (var (key, value) in swaggerDoc.Paths)
{
replacements.Add(key.Replace("v{version}", swaggerDoc.Info.Version,
StringComparison.InvariantCulture), value);
}
swaggerDoc.Paths = replacements;
}
}
next 在 ConfigureServices 方法中添加以下代码 startup:
protected virtual IEnumerable<int> Versions => new[] {1};
services.AddSwaggerGen(options =>
{
Versions.ToList()
.ForEach(v =>
options.SwaggerDoc($"v{v}",
new OpenApiInfo
{
Title = $"Versioned Api:v{v}", Version = $"v{v}"
}));
options.OperationFilter<RemoveVersionFromParameter>();
options.DocumentFilter<ReplaceVersionWithExactValueInPath>();
options.RoutePrefix = string.Empty;
});
then 在 configure 方法中添加以下代码 startup:
app.UseSwagger();
app.UseSwaggerUI(options =>
{
Versions.ToList()
.ForEach(v => options.SwaggerEndpoint($"/swagger/v{v}/swagger.json", $"Versioned Api:v{v}"));
options.RoutePrefix = string.Empty;
});