web-dev-qa-db-ja.com

SwaggerがASP.NET WebApiアプリの複数のバージョンで正しく機能しない

これで私を助けてください、それは最初は簡単に見えました、今私はプロジェクトに遅れています:

ASP.NET WebApiプロジェクトのAPIバージョン管理をSwaggerとともにセットアップしようとしています。 APIのバージョン管理は適切に機能し、異なるバージョンを呼び出すと正しい結果が返されます(以下を参照)。

逆に、Swaggerは両方のバージョンを提供できません。デバッグ中に、SwaggerConfig.csでc.MultipleApiVersions(...)が呼び出されると、コントローラーがapiDesc.ActionDescriptor.ControllerDescriptorは常にPingControllerであり、決してPing11Controller

誰かがこれを解決するために何をする必要があるかを指摘し、Swaggerを両方のバージョンで機能させることはできますか?

以下では、Swaggerがv1.0でのみ機能するのに対して、APIバージョン管理のコードと証明が正常に機能します。

ありがとうございました!

API v1.0の呼び出しは機能します:enter image description here

API v1.1の呼び出しも機能します:enter image description here

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>
13
Sorin Comanescu

それを解決する:

  1. Microsoft.AspNet.WebApi.Versioning.ApiExplorerパッケージを追加する
  2. 以下のようにバージョン管理されたAPI Explorerを使用します(初期化の問題のため、WebApiConfig.csのSwaggerConfig.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);
            });
    
2
Sorin Comanescu

enter image description here

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();
            });
    }
}
1
Narottam Goyal