使用 Swashbuckle / Swagger 的 C# 版本化 WebApi 文档

C# versioned WebApi documentation using Swashbuckle / Swagger

我有一个具有多个版本的 C# WebApi,我想使用 Swashbuckle/Swagger,使用 .net core 3.1 对其进行记录。我已经尝试按照我能找到的指南进行操作,但我似乎遗漏了一些东西,因为 swagger 一直显示一个空列表,就像我的项目不包含 API.

设置如下:

Startup.cs

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.AddApiVersioning(o => { });

            var apiExplorer = services.AddVersionedApiExplorer(options => {
                options.GroupNameFormat = "'v'VVV";
                options.SubstituteApiVersionInUrl = true;
            });

            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1.0", new OpenApiInfo()
                {
                    Title = "My API v1.0",
                    Version = "v1.0"
                });

                options.SwaggerDoc("v1.1", new OpenApiInfo()
                {
                    Title = "My API v1.1",
                    Version = "v1.1"
                });

                options.SwaggerDoc("v2.0", new OpenApiInfo()
                {
                    Title = "My API v2.0",
                    Version = "v2.0"
                });
            });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.DefaultModelsExpandDepth(0);
                c.SwaggerEndpoint($"/swagger/v1.0/swagger.json", "my API 1.0");
            });
        }

我有这样定义的控制器:

    [ApiController]
    [ApiVersion("1.0")]
    [Route("api/weather/ByQuerySeparateClasses")]
    public class ByQuerySeparateClassesV1Controller : ControllerBase
    {
        [HttpGet("read")]
        public WeatherResponse Get()
        {
            return new WeatherResponse() { Summary = "v1 by path, different controllers" };
        }
    }

    [ApiController]
    [ApiVersion("2.0")]
    [Route("api/weather/ByQuerySeparateClasses")]
    public class ByQuerySeparateClassesV2Controller : ControllerBase
    {
        [HttpGet("read")]
        public WeatherResponse Get()
        {
            return new WeatherResponse() { Summary = "v2 by path, different controllers" };
        }
    }

当我 运行 这个 API 时,这是生成的 JSON,一个空列表,好像没有看到我的 API。

GET http://localhost:5000/swagger/v1.0/swagger.json
{
  "openapi": "3.0.1",
  "info": {
    "title": "My API v1.0",
    "version": "v1.0"
  },
  "paths": { },
  "components": { }
}

我做错了什么?或者任何提示我如何进一步诊断正在发生的事情?

完整示例可在此处找到:https://github.com/mmgagnon/versioned-api-with-swagger

这是一个像下面这样的工作演示:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddApiVersioning(o =>
    {               
        o.AssumeDefaultVersionWhenUnspecified = true;
        o.DefaultApiVersion = new ApiVersion(1, 0);
        o.ApiVersionReader = new UrlSegmentApiVersionReader();
    });

    services.AddVersionedApiExplorer(options => {
        options.GroupNameFormat = "'v'VVV";
        options.SubstituteApiVersionInUrl = true;
    });

    services.AddSwaggerGen(options =>
    {
        //add this...
        options.DocInclusionPredicate((docName, apiDesc) =>
        {
            if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo))
            {
                return false;
            }

            IEnumerable<ApiVersion> versions = methodInfo.DeclaringType
                .GetCustomAttributes(true)
                .OfType<ApiVersionAttribute>()
                .SelectMany(a => a.Versions);

            return versions.Any(v => $"v{v.ToString()}" == docName);
        });
    
        options.SwaggerDoc("v1.0", new OpenApiInfo()
        {
            Title = "My API v1.0",
            Version = "v1.0"
        });

        options.SwaggerDoc("v1.1", new OpenApiInfo()
        {
            Title = "My API v1.1",
            Version = "v1.1"
        });

        options.SwaggerDoc("v2.0", new OpenApiInfo()
        {
            Title = "My API v2.0",
            Version = "v2.0"
        });
    });
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseApiVersioning();
    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });

    app.UseSwagger(swagger => {
    });

    app.UseSwaggerUI(c =>
    {
        c.DefaultModelsExpandDepth(0);
        c.SwaggerEndpoint($"/swagger/v1.0/swagger.json", "my API 1.0");
        c.SwaggerEndpoint($"/swagger/v2.0/swagger.json", "my API 2.0");
    });
}