Swagger 版本控制不起作用。它显示所有端点,尽管选择了 API 版本

Posted

技术标签:

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

全部!

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

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

我的控制器是:


namespace Application.Controllers

    [ApiVersion("1")]
    [ApiVersion("2")]
    [ApiController]
    [Route("api/vversion: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 个端点?

【问题讨论】:

【参考方案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 $"vspecificVersion" == version;
                    

                    var versions = endpointMetadata
                            .Where(data => data is ApiVersionAttribute)
                            .SelectMany(data => (data as ApiVersionAttribute).Versions)
                            .Select(apiVersion => apiVersion.ToString());

                    return versions.Any(v => $"vv" == 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 上处理的相关问题非常相似。

【讨论】:

以上是关于Swagger 版本控制不起作用。它显示所有端点,尽管选择了 API 版本的主要内容,如果未能解决你的问题,请参考以下文章

Fluent Assertions 检查是不是所有端点都具有特定的 swagger 属性

所有控制器的全局标头(nestJs swagger)

在具有相同名称的不同名称空间中招摇不同的类不起作用

使用 Swagger UI 和 Swashbuckle 按消费者过滤 API 端点

Laravel 版本 - 4.2 注销不起作用

Springboot:Swagger UI 格式在 AWS 中显示不正确