【问题标题】:Swagger versioning is not working. It displays all endpoints, despite the selected API versionSwagger 版本控制不起作用。它显示所有端点,尽管选择了 API 版本
【发布时间】:2020-09-04 08:57:56
【问题描述】:

全部!

我在 ASP.NET Core 3.1 应用程序中使用 Swagger。

我需要为新版本的 API 创建一个端点,并使用与以前版本相同的路由。

我的控制器是:


namespace Application.Controllers
{
    [ApiVersion("1")]
    [ApiVersion("2")]
    [ApiController]
    [Route("api/v{version:apiVersion}")]
    public class CustomController: ControllerBase
    {
        [HttpGet]
        [Route("result")]
        public IActionResult GetResult()
        {
            return Ok("v1")
        }

        [HttpGet]
        [MapToApiVersion("2")]
        [Route("result")]
        public IActionResult GetResult(int number)
        {
            return Ok("v2")
        }
    }
}

我的配置:

            services.AddApiVersioning(
                options =>
                {
                    options.ReportApiVersions = true;
                });

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc($"v1", new OpenApiInfo { Title = "api1", Version = $"v1" });

                c.SwaggerDoc($"v2", new OpenApiInfo { Title = "api2", Version = $"v2" });         
         

                c.OperationFilter<RemoveVersionParameterFilter>();
                c.DocumentFilter<ReplaceVersionWithExactValueInPathFilter>();
                c.EnableAnnotations();
            });
app.UseSwagger().UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint($"/swagger/v1/swagger.json", $"api1 v1");
                c.SwaggerEndpoint($"/swagger/v2/swagger.json", $"api2 v2");
            });

加载后出现错误:Fetch error undefined /swagger/v1/swagger.json 但是如果我将第二条路由更改为“resutlTwo”,我可以大摇大摆地观察两个端点,忽略当前版本(api1 v1 或 api2 v2)

如何才能看到每个 API 版本只有 1 个端点?

【问题讨论】:

    标签: asp.net-core swagger swashbuckle.aspnetcore


    【解决方案1】:

    感谢Roar S. 的帮助!

    我刚刚加了

     services.AddApiVersioning(apiVersioningOptions =>
                {
                    apiVersioningOptions.ReportApiVersions = true;
                    apiVersioningOptions.ApiVersionReader = new UrlSegmentApiVersionReader();
                });
    

     c.DocInclusionPredicate((version, desc) =>
                    {
                        var endpointMetadata = desc.ActionDescriptor.EndpointMetadata;
    
                        if (!desc.TryGetMethodInfo(out MethodInfo methodInfo))
                        {
                            return false;
                        }
    
                        var specificVersion = endpointMetadata
                                .Where(data => data is MapToApiVersionAttribute)
                                .SelectMany(data => (data as MapToApiVersionAttribute).Versions)
                                .Select(apiVersion => apiVersion.ToString())
                                .SingleOrDefault();
    
                        if (!string.IsNullOrEmpty(specificVersion))
                        {
                            return $"v{specificVersion}" == version;
                        }
    
                        var versions = endpointMetadata
                                .Where(data => data is ApiVersionAttribute)
                                .SelectMany(data => (data as ApiVersionAttribute).Versions)
                                .Select(apiVersion => apiVersion.ToString());
    
                        return versions.Any(v => $"v{v}" == version);
                    });
    

    并将端点拆分为不同的文件。

    【讨论】:

    • 感谢分享您的工作配置。是的,我的配置有点过分,但我想展示我是如何测试你的代码的。在许多情况下,可能还缺少其他部分。
    【解决方案2】:

    我刚刚使用此设置测试了您的情况。您缺少UrlSegmentApiVersionReader

    public class SwaggerOptions
    {
        public string Title { get; set; }
        public string JsonRoute { get; set; }
        public string Description { get; set; }
        public List<Version> Versions { get; set; }
    
        public class Version
        {
            public string Name { get; set; }
            public string UiEndpoint { get; set; }
        }
    }
    

    在启动#ConfigureServices 中

            // Configure versions 
            services.AddApiVersioning(apiVersioningOptions =>
            {
                apiVersioningOptions.ReportApiVersions = true;
                apiVersioningOptions.ApiVersionReader = new UrlSegmentApiVersionReader();
            });
    
            // Register the Swagger generator, defining 1 or more Swagger documents
            services.AddSwaggerGen(swaggerGenOptions =>
            {
                var swaggerOptions = new SwaggerOptions();
                Configuration.GetSection("Swagger").Bind(swaggerOptions);
    
                foreach (var currentVersion in swaggerOptions.Versions)
                {
                    swaggerGenOptions.SwaggerDoc(currentVersion.Name, new OpenApiInfo
                    {
                        Title = swaggerOptions.Title,
                        Version = currentVersion.Name,
                        Description = swaggerOptions.Description
                    });
                }
    
                swaggerGenOptions.DocInclusionPredicate((version, desc) =>
                {
                    if (!desc.TryGetMethodInfo(out MethodInfo methodInfo))
                    {
                        return false;
                    }
                    var versions = methodInfo.DeclaringType.GetConstructors()
                        .SelectMany(constructorInfo => constructorInfo.DeclaringType.CustomAttributes
                            .Where(attributeData => attributeData.AttributeType == typeof(ApiVersionAttribute))
                            .SelectMany(attributeData => attributeData.ConstructorArguments
                                .Select(attributeTypedArgument => attributeTypedArgument.Value)));
    
                    return versions.Any(v => $"{v}" == version);
                });
    
                swaggerGenOptions.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"));
                
                ... some filter settings here 
            });
    

    在启动#配置中

    var swaggerOptions = new SwaggerOptions();
    Configuration.GetSection("Swagger").Bind(swaggerOptions);
    app.UseSwagger(option => option.RouteTemplate = swaggerOptions.JsonRoute);
    
    app.UseSwaggerUI(option =>
    {
      foreach (var currentVersion in swaggerOptions.Versions)
      {
        option.SwaggerEndpoint(currentVersion.UiEndpoint, $"{swaggerOptions.Title} {currentVersion.Name}");
      }
    });
    

    appsettings.json

    {
      "Swagger": {
        "Title": "App title",
        "JsonRoute": "swagger/{documentName}/swagger.json",
        "Description": "Some text",
        "Versions": [
          {
            "Name": "2.0",
              "UiEndpoint": "/swagger/2.0/swagger.json"
          },
          {
            "Name": "1.0",
            "UiEndpoint": "/swagger/1.0/swagger.json"
          }
        ]
      }
    }
    

    此代码与我在 SO 上处理的相关问题非常相似。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-28
      • 2021-06-19
      • 1970-01-01
      • 2014-08-24
      • 1970-01-01
      • 2019-02-01
      相关资源
      最近更新 更多