[英]Swagger not working correctly with multiple versions of ASP.NET WebApi app
請幫我解決這個問題,起初看起來很簡單,現在我在項目中遲到了:
我正在嘗試為 ASP.NET WebApi 項目以及 Swagger 設置 API 版本控制。 API 版本控制工作正常,調用不同的版本會返回正確的結果(見下文)。
相反,Swagger 無法為這兩個版本提供服務。 在調試時,我注意到,當c.MultipleApiVersions(...)
獲取SwaggerConfig.cs叫,控制器報告apiDesc.ActionDescriptor.ControllerDescriptor
總是PingController
永不Ping11Controller
。
有人可以指出需要做些什么來解決這個問題並使 Swagger 也適用於兩個版本嗎?
下面,API 版本控制的代碼和證明工作正常,而 Swagger 僅適用於 v1.0。
謝謝!
Swagger for v1.0 很好:( http://localhost:50884/v1.0/swagger )
{
"swagger":"2.0",
"info":{
"version":"v1.0",
"title":"My API v1.0"
},
"host":"localhost:50884",
"schemes":[
"http"
],
"paths":{
"/api/ping":{
"get":{
"tags":[
"Ping"
],
"summary":"Get a pong.",
"operationId":"GetAPong",
"consumes":[
],
"produces":[
"application/json",
"text/json",
"application/xml",
"text/xml"
],
"responses":{
"200":{
"description":"OK"
},
"404":{
"description":"NotFound"
}
}
}
}
},
"definitions":{
}
}
v1.1 的 Swagger 為空:( http://localhost:50884/v1.1/swagger )
{
"swagger":"2.0",
"info":{
"version":"v1.1",
"title":"My API v1.1"
},
"host":"localhost:50884",
"schemes":[
"http"
],
"paths":{
},
"definitions":{
}
}
App_Start\\WebApiConfig.cs:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.AddApiVersioning(options => {
options.ReportApiVersions = true;
});
var constraintResolver = new System.Web.Http.Routing.DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("apiVersion", typeof(Microsoft.Web.Http.Routing.ApiVersionRouteConstraint));
config.MapHttpAttributeRoutes(constraintResolver);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
App_Start\\SwaggerConfig.cs:
public class SwaggerConfig
{
static string XmlCommentsFilePath
{
get
{
var basePath = System.AppDomain.CurrentDomain.RelativeSearchPath;
var fileName = typeof(SwaggerConfig).GetTypeInfo().Assembly.GetName().Name + ".xml";
return Path.Combine(basePath, fileName);
}
}
public static void Register()
{
var configuration = GlobalConfiguration.Configuration;
GlobalConfiguration.Configuration.EnableSwagger("{apiVersion}/swagger", c => {
c.OperationFilter<SwaggerDefaultValues>();
c.MultipleApiVersions((System.Web.Http.Description.ApiDescription apiDesc, string targetApiVersion) =>
{
var attr = apiDesc.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<Microsoft.Web.Http.ApiVersionAttribute>().FirstOrDefault();
if (attr == null && (targetApiVersion == "v1" || targetApiVersion == "v1.0")) return true;
var match = (attr != null) && (attr.Versions.FirstOrDefault(v => "v" + v.ToString() == targetApiVersion) != null);
return match;
},
(vc) =>
{
vc.Version("v1.1", "My API v1.1");
vc.Version("v1.0", "My API v1.0");
});
c.IncludeXmlComments(SwaggerConfig.XmlCommentsFilePath);
})
.EnableSwaggerUi(c => {
c.DocExpansion(DocExpansion.List);
c.EnableDiscoveryUrlSelector();
});
}
}
v1.0 和 v1.1 的控制器(位於相同的命名空間中)
[ApiVersion("1.0")]
[RoutePrefix("api")]
[ControllerName("Ping")]
public class PingController : ApiController
{
[HttpGet]
[Route("ping")]
[SwaggerOperation("GetAPong")]
[SwaggerResponse(HttpStatusCode.OK)]
[SwaggerResponse(HttpStatusCode.NotFound)]
public string Get()
{
return "Pong v1.0";
}
}
[ApiVersion("1.1")]
[RoutePrefix("api")]
[ControllerName("Ping")]
public class Ping11Controller : ApiController
{
[HttpGet]
[Route("ping")]
[SwaggerOperation("GetAPong")]
[SwaggerResponse(HttpStatusCode.OK)]
[SwaggerResponse(HttpStatusCode.NotFound)]
public string Get()
{
return "Pong v1.1";
}
}
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.Versioning" version="2.1.0" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.7" targetFramework="net46" />
<package id="Microsoft.IdentityModel.Logging" version="1.1.4" targetFramework="net46" />
<package id="Microsoft.IdentityModel.Tokens" version="5.1.4" targetFramework="net46" />
<package id="Microsoft.Net.Compilers" version="2.3.2" targetFramework="net46" developmentDependency="true" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net46" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net46" />
<package id="NLog" version="4.4.12" targetFramework="net46" />
<package id="Swashbuckle" version="5.6.0" targetFramework="net46" />
<package id="Swashbuckle.Core" version="5.6.0" targetFramework="net46" />
<package id="System.IdentityModel.Tokens.Jwt" version="5.1.4" targetFramework="net46" />
<package id="WebActivatorEx" version="2.2.0" targetFramework="net46" />
</packages>
通過以下方式解決:
使用如下版本化 API 資源管理器(請注意,由於初始化問題,我不得不將代碼從 SwaggerConfig.cs 移到 WebApiConfig.cs 中):
var apiExplorer = config.AddVersionedApiExplorer(options => { options.GroupNameFormat = "'v'VVV"; }); var versionSupportResolver = new Func<ApiDescription, string, bool>((apiDescription, version) => apiDescription.GetGroupName() == version); var versionInfoBuilder = new Action<VersionInfoBuilder>(info => { foreach (var group in apiExplorer.ApiDescriptions) { info.Version(group.Name, $"MyAPI v{group.ApiVersion}"); } }); config .EnableSwagger("{apiVersion}/swagger", swagger => { swagger.OperationFilter<SwaggerDefaultValues>(); swagger.MultipleApiVersions(versionSupportResolver, versionInfoBuilder); swagger.IncludeXmlComments(WebApiConfig.XmlCommentsFilePath); }) .EnableSwaggerUi(swaggerUi => { swaggerUi.EnableDiscoveryUrlSelector(); swaggerUi.DocExpansion(DocExpansion.List); });
ValueV1Controller.cs
[RoutePrefix("api/v1/value")]
public class ValueV1Controller : ApiController
{
[Route("get")]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
ValueV2Controller.cs
[RoutePrefix("api/v2/value")]
public class ValueV2Controller : ApiController
{
[Route("get")]
public IEnumerable<string> Get()
{
return new string[] { "value1.2", "value2.2" };
}
}
SwaggerConfig.cs
public class SwaggerConfig
{
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.MultipleApiVersions(
(apiDesc, version) =>
{
var path = apiDesc.RelativePath.Split('/');
var pathVersion = path[1];
return CultureInfo.InvariantCulture.CompareInfo.IndexOf(pathVersion, version, CompareOptions.IgnoreCase) >= 0;
},
(vc) =>
{
vc.Version("v2", "Swashbuckle Dummy API V2");
vc.Version("v1", "Swashbuckle Dummy API V1");
});
})
.EnableSwaggerUi(c =>
{
c.EnableDiscoveryUrlSelector();
});
}
}
我有同樣的錯誤,但為我解決的是將EnableSwagger擴展方法中的templateRoute從swagger/docs/{apiVersion}更改為swagger/{apiVersion}/docs 。 我認為當 api 版本在路由的末尾時,次要版本存在解析問題(可能是因為它包含一個“.”)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.