我与Swagger有一个奇怪的问题。。。我正在使用版本化的API,事实上版本化正在发挥作用。。。但是,我有两个问题感到困惑。我已经配置了两个独立的API版本,这样我就可以测试了。。。v1.0和v2.0版本。我已经将版本控制的属性以及它们的操作放入控制器中,以将事情稍微混合起来,看看Swagger中的版本控制是否只显示与每个版本相关的端点。
我遇到的问题是:a.(每个端点的Swagger输出中的渲染路由没有以major.minor格式(即v1.0(显示/api/v1/&";。我希望这条路线是"/api/v.0/…";。有人知道怎么解决这个问题吗?b.(无论我从页面顶部的下拉列表中选择哪一个API版本,Swagger都会产生所有端点(v1.0和v2.0(。我认为正确的功能是过滤以仅显示所选版本的端点,但这并没有发生。
注意:在下面的屏幕截图中,尽管我已经将所有控制器和操作版本控制属性设置为";v2.0";它们被显示在";v1.0";版本页面。
示例截图
Here is my startup config and example of my controller and actions:
/// <summary>
/// Jobs API for CRUD job
/// </summary>
[ApiVersion("1.0")]
[ApiVersion("2.0")]
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
public class JobsController : Controller
{
/// <summary>
/// Gets all jobs using the API
/// </summary>
/// <returns>Return a list of jobs</returns>
[ApiVersion("2.0")]
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<Job>), (int)HttpStatusCode.OK)]
public IActionResult Get()
{
return Ok("hello");
}
/// <summary>
/// get Job using the id
/// </summary>
/// <param name="id">job id</param>
/// <returns>Job for the ID</returns>
[ApiVersion("2.0")]
[HttpGet("{id}")]
[ProducesResponseType(typeof(IEnumerable<Job>), (int)HttpStatusCode.OK)]
public IActionResult Get(int id)
{
if (id == 0)
{
return BadRequest();
}
//var jobExists = Jobs.Exists(j => j.Id == id);
//if (jobExists == false)
//{
// return NotFound($"Job with Id not found: {id}");
//}
return Ok();
}
启动:#区域设置API版本区域
// NOTE: declaration order matters for versioning APIs to be setup correctly
services.AddVersionedApiExplorer(o => // this is required to support swagger gathering info on all of the existing endpoints for ALL versions of APIs
{
o.GroupNameFormat = "'v'VVV";
o.SubstituteApiVersionInUrl = true;
});
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
});
#endregion
#region Swagger Setup Region
#region Swashbuckle Overview - an automated Swagger content generator -- See: https://github.com/domaindrivendev/Swashbuckle.WebApi
// Seamlessly adds a Swagger to WebApi projects! Combines ApiExplorer and Swagger/ swagger - ui to provide a rich discovery, documentation and playground experience
// to your API consumers.
// In addition to its Swagger generator, Swashbuckle also contains an embedded version of swagger - ui which it will automatically serve up once Swashbuckle is installed.
// This means you can complement your API with a slick discovery UI to assist consumers with their integration efforts.Best of all, it requires minimal coding and maintenance,
// allowing you to focus on building an awesome API!
// And that's not all ...
// Once you have a Web API that can describe itself in Swagger, you've opened the treasure chest of Swagger-based tools including a client generator that can be targeted to a wide
// range of popular platforms. See swagger-codegen for more details.
//
// Features:
// Auto-generated Swagger 2.0
// * Seamless integration of swagger-ui
// * Reflection - based Schema generation for describing API types
// * Extensibility hooks for customizing the generated Swagger doc
// * Extensibility hooks for customizing the swagger - ui
// * Out - of - the - box support for leveraging Xml comments
// * Support for describing ApiKey, Basic Auth and OAuth2 schemes... including UI support for the Implicit OAuth2 flow
//
// How does Swashbuckle find the endpoints that it needs to document?...
// Swashbuckle requires the use of routing attributes to find the endpoints... if you are using conventional routing (as opposed to attribute routing), any controllers and the actions
// on those controllers that use conventional routing will not be represented in ApiExplorer, which means Swashbuckle won't be able to find those controllers
// and generate Swagger operations from them. For example:
//
// [Route("example")]
// public class ExampleController : Controller
//
// IMPORTANT: Ensure your API actions and parameters are decorated with explicit "Http" and "From" bindings.
// [HttpPost]
// public void CreateProduct([FromBody] Product product)
// ...
// [HttpGet]
// public IEnumerable<Product> SearchProducts([FromQuery] string keywords)
// NOTE: If you omit the explicit parameter bindings, the generator will describe them as "query" params by default.
// TIP: to correctly setup versioning in conjunction with Swagger, see: https://stackoverflow.com/questions/60084877/swagger-not-finding-apiversion-ed-actions
#endregion
// Add Open API (Swagger) functionality via Swashbuckle -- for full options, see: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md#configuration--customization
// TIP: Adding triple-slash comments /// to an action enhances the Swagger UI by adding the description to the section header.
// TIP: Add a <remarks> element to the Create action method documentation. It supplements information specified in the <summary> element and provides a more robust Swagger UI. The <remarks> element content can consist of text, JSON, or XML.
services.AddSwaggerGen(c => // Configuration documentation -- See: https://learn.microsoft.com/en-us/samples/aspnet/aspnetcore.docs/getstarted-swashbuckle-aspnetcore/?tabs=visual-studio
{
// configure swagger to handle versioning, otherwise this error is presented: "No operations defined in spec!"
c.DocInclusionPredicate((docName, apiDesc) =>
{
if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo))
{
return false;
}
IEnumerable<ApiVersion> versions = methodInfo.DeclaringType
.GetCustomAttributes(true)
.OfType<ApiVersionAttribute>()
.SelectMany(a => a.Versions);
return versions.Any(v => $"v{v.ToString()}" == docName);
});
c.SwaggerDoc("v1.0", new OpenApiInfo
{
Version = "v1.0",
Title = "test Software blah API version 1.0",
Description = "A RESTful web API to access and manage blah metric reporting.",
TermsOfService = new Uri("https://test.com/termsofservice"),
Contact = new OpenApiContact
{
Name = "test Software",
Email = "support@test.com",
Url = new Uri("https://test.com/apisupport"),
},
License = new OpenApiLicense
{
Name = "Use License: CDDL-1.0",
Url = new Uri("https://opensource.org/licenses/CDDL-1.0"),
}
});
c.SwaggerDoc("v2.0", new OpenApiInfo
{
Version = "v2.0",
Title = "test Software blah API Version 2.0",
Description = "A RESTful web API to access and manage blah metric reporting.",
TermsOfService = new Uri("https://test.com/termsofservice"),
Contact = new OpenApiContact
{
Name = "test Software",
Email = "support@test.com",
Url = new Uri("https://test.com/apisupport"),
},
License = new OpenApiLicense
{
Name = "Use License: CDDL-1.0",
Url = new Uri("https://opensource.org/licenses/CDDL-1.0"),
}
});
// Apply the API versioning filters for swagger
//c.OperationFilter<SwaggerRemoveVersionFromParameter>();
//c.DocumentFilter<SwaggerReplaceVersionWithExactValueInPath>();
c.EnableAnnotations();
c.ExampleFilters();
c.OperationFilter<AddHeaderOperationFilter>("correlationId", "Correlation Id for the request", false); // adds any string you like to the request headers - in this case, a correlation id
c.OperationFilter<AddResponseHeadersFilter>(); // [SwaggerResponseHeader]
// Set the comments path for the Swagger JSON and UI.
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath); // standard Swashbuckle functionality, this needs to be before c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>()
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>(); // Adds "(Auth)" to the summary so that you can see which endpoints have Authorization
// or use the generic method, e.g. c.OperationFilter<AppendAuthorizeToSummaryOperationFilter<MyCustomAttribute>>();
// add Security information to each operation for OAuth2
c.OperationFilter<SecurityRequirementsOperationFilter>();
// or use the generic method, e.g. c.OperationFilter<SecurityRequirementsOperationFilter<MyCustomAttribute>>();
// if you're using the SecurityRequirementsOperationFilter, you also need to tell Swashbuckle you're using OAuth2
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Description = "Standard Authorization header using the Bearer scheme. Example: "bearer {token}"",
In = ParameterLocation.Header,
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
});
});
services.AddSwaggerExamplesFromAssemblies(Assembly.GetEntryAssembly()); // This will register your "examples" with the ServiceProvider.
#endregion
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1.0/swagger.json", "test API v1.0");
c.SwaggerEndpoint("/swagger/v2.0/swagger.json", "test API v2.0");
});
已解决!好的…
信贷应该转到https://dev.to/htissink/versioning-asp-net-core-apis-with-swashbuckle-making-space-potatoes-v-x-x-x-3po7这里的评论。。。https://dev.to/codeswayslay/comment/paff.
秘制酱汁是:
a.(使用MapToApiVersion Swagger属性装饰控制器的操作方法。。。例如:[MapToApiVersion("1.0")]
b.(确保您的DocInclusionPredice lambda设置如下:
setup.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));
});
请密切关注maps变量,因为它可以找到映射到特定版本的所有属性。。。以及上面显示的返回分配。