【问题标题】:asp.net core swashbuckle how to use versioning in same controllerasp.net core swashbuckle 如何在同一控制器中使用版本控制
【发布时间】:2020-10-08 13:11:24
【问题描述】:

当在 asp.net 核心中使用带有 swashbuckle 的版本控制时,默认情况下,您不能在同一个控制器中拥有多个方法:

[Route("v{version:apiVersion}/[controller]")]
[ApiVersion("1")]
[ApiVersion("2")]
[ApiController]
public class TestController : ControllerBase
{
    /// <summary>
    /// test ver 1
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [MapToApiVersion("1")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public string Get()
    {
        return "Version 1";
    }

    /// <summary>
    /// test ver 2
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [MapToApiVersion("2")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public string Get2()
    {
        return "Version 2";
    }
}

默认情况下,您将收到错误消息

Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: 用于操作的冲突方法/路径组合“GET v{version}/Test”

  • ...Controllers.TestController.Get,...TestController.Get2

因为 swagger-ui 通过同一路线识别这两种方法

localhost/v{version:apiVersion}/Test

基本的 swashbuckle 解决方案是为每个版本的方法设置两个单独的控制器。这对我的用例来说是个糟糕的解决方案。

【问题讨论】:

    标签: c# asp.net-core swashbuckle


    【解决方案1】:

    解决方案是在 swagger setter 中手动检查版本。就我而言,我还添加了支持的版本列表。

    所以你必须在 Startup.cs 添加这个:

    private readonly string[] supportedVersions = new string[] { "1", "2" };
    
    public void ConfigureServices(IServiceCollection services)
    {
    ...
    services.AddApiVersioning();
    services.AddSwaggerGen(c =>
    {
                
        c.DocInclusionPredicate((docName, apiDesc) =>
        {
            var metadata = apiDesc.ActionDescriptor.EndpointMetadata;
            var apiVersionModel = metadata.Where(x => x.GetType() == typeof(ApiVersionAttribute)).Cast<ApiVersionAttribute>();
            var supportedVersions = metadata.Where(x => x.GetType() == typeof(MapToApiVersionAttribute)).Cast<MapToApiVersionAttribute>();
            if (apiVersionModel.IsNullOrEmpty() || supportedVersions.IsNullOrEmpty())
            {
                return false;
            }
    
            var apiVersions = apiVersionModel.SelectMany(x => x.Versions.Select(y => y.MajorVersion));
            var versions = supportedVersions.SelectMany(x => x.Versions.Select(y => y.MajorVersion));
    
            return apiVersions.Any(v => $"v{v.ToString()}" == docName) && versions.Any(v => $"v{v.ToString()}" == docName);
        });
        c.DocumentFilter<ReplaceVersionWithExactValueInPathFilter>();
        c.OperationFilter<RemoveVersionParameterFilter>();
        c.EnableAnnotations();
        supportedVersions.ForEach(sv =>
        {
            c.SwaggerDoc($"v{sv}", new OpenApiInfo()
            {
                Version = $"v{sv}",
                Title = $"API v{ sv }",
                Description = "My web api",
            });
        });
        var baseDirectory = AppContext.BaseDirectory;
        var xmlFiles = Directory.EnumerateFiles(baseDirectory, "*.xml");
    
        xmlFiles.ForEach(x => c.IncludeXmlComments(x));
    });
    ...
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
                app.UseSwaggerUI(c =>
            {
                supportedVersions.ForEach(sv =>
                {
                    c.SwaggerEndpoint($"/swagger/v{sv}/swagger.json", $"My api v{sv}");
                });
            });
        }
    

    和分隔文件两种方法以避免在 UI 中将版本显示为参数。否则,您将看到带有版本参数而不是版本本身的端点。

    public class RemoveVersionParameterFilter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var versionParameter = operation.Parameters.FirstOrDefault(p => p.Name == "version");
            if (versionParameter == default(OpenApiParameter))  return;
            var parameters = operation.Parameters.ToList();
            operation.Parameters.Remove(versionParameter);
        }
    }
    
    public class ReplaceVersionWithExactValueInPathFilter : IDocumentFilter
    {
        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            var paths = new OpenApiPaths();
            foreach (var path in swaggerDoc.Paths)
            {
                
                paths.Add(path.Key.Replace("v{version}", swaggerDoc.Info.Version), path.Value);
            }
            swaggerDoc.Paths = paths;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-19
      • 2019-11-25
      • 2016-11-13
      • 2018-03-04
      • 1970-01-01
      • 2016-04-30
      • 2019-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多