【问题标题】:.Net core 2.2 API versioning and proper routing.Net core 2.2 API 版本控制和正确路由
【发布时间】:2020-06-26 04:48:15
【问题描述】:

我正在创建一个 API。我使用 swagger,但由于控制器和操作数量巨大,我想按域拆分 API 端点。为此,我考虑了 API 的版本控制。我考虑过使用 ApiVersion 的状态。我的控制器的代码如下。

[ApiVersion("1.0-First")] //This is ApiVersion MajorVersion = 1, Status = "First"
[Route("api/v{version:apiVersion}/[controller]")]
public class FirstController

[ApiVersion("1.0-Second")]
[Route("api/v{version:apiVersion}/other")]
public class SecondController

我的招摇看起来不错,API 部分的定义也很好。 (我知道路径应该没有大写字母 - 这仅用于测试目的)

但是 swagger 无法到达任何端点。因为有效端点位于 /api/v1.0-First/First 而不是 /api/v1/First。
我的启动类如下所示:

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvcCore().AddApiExplorer();
        services.AddApiVersioning(c =>
        {
            c.ApiVersionReader = ApiVersionReader.Combine(
                new QueryStringApiVersionReader("V"),
                new UrlSegmentApiVersionReader());
            c.ReportApiVersions = false;
            c.DefaultApiVersion = new ApiVersion(1, 0);
        });

        services.AddVersionedApiExplorer(options =>
        {
            options.SubstituteApiVersionInUrl = true;
            options.SubstitutionFormat = "V";
            options.DefaultApiVersion = new ApiVersion(1, 0);
        });

        services.RegisterSwaggerConfiguration();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseDeveloperExceptionPage();
        app.UseHttpsRedirection();
        app.UseMvc();
        app.AddSwagger(app.ApplicationServices.GetService<IApiVersionDescriptionProvider>(), Configuration);
    }

我写了一些静态类来添加基于 IApiVersionDescriptionProvider 的依赖项

    public static class SwaggerExtension
{
    public static void RegisterSwaggerConfiguration(this IServiceCollection services)
    {
        services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
        services.AddSwaggerGen();
    }

    public static void AddSwagger(this IApplicationBuilder app, IApiVersionDescriptionProvider provider, IConfiguration configuration)
    {
        var prefix = "swagger";
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.RoutePrefix = string.Empty;
            foreach (var description in provider.ApiVersionDescriptions)
            {
                c.SwaggerEndpoint($"{prefix}/{description.GroupName}/swagger.json", description.GroupName);
            }
        });
    }
}

还有另一个用于 SwaggerDoc 生成的类。

    public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
    private readonly IApiVersionDescriptionProvider provider;
    private readonly IConfiguration configuration;


    public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider, IConfiguration configuration)
    {
        this.provider = provider;
        this.configuration = configuration;
    }

    public void Configure(SwaggerGenOptions options)
    {
        foreach (var description in provider.ApiVersionDescriptions)
        {
            options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));
        }
    }

    private OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description)
    {
        var info = new OpenApiInfo()
        {
            Title = description.GroupName,
            Version = description.ApiVersion.ToString(),
        };

        if (description.IsDeprecated)
        {
            info.Description += " This API version has been deprecated.";
        }

        return info;
    }
}

我想让路由工作为 api/v1/First 或 api/v1.0/First(这应该没关系)。
也许编写一些自定义中间件来处理这种情况是个好主意?
到目前为止,我已经没有想法了,总的来说,我找不到任何关于使用 ApiVersion 状态的文章。
编辑: 已更改标题。

【问题讨论】:

    标签: .net-core routes swagger versioning swashbuckle


    【解决方案1】:

    我们前段时间遇到过类似的问题。我们需要按客户权限/域来拆分 Api。这项研究也花了一些时间:),请注意我们正在使用 NSwag。

    正如您已经提到的(自定义中间件),我们创建了自定义 OperationProcessor 并使用了基本类型检查。看一个例子:

    services.AddOpenApiDocument(document =>
            {
                document.Title = "API A";
                document.OperationProcessors.Insert(0, new IncludeAApiControllersInSwagger());
            });
    
    services.AddOpenApiDocument(document =>
            {
                document.Title = "API B";
                document.OperationProcessors.Insert(0, new IncludeBApiControllersInSwagger());
            });
    

    然后

    private class IncludeAApiControllersInSwagger : IOperationProcessor
        {
            public bool Process(OperationProcessorContext context)
            {
                 return IsControllerInType(context, typeof(AApiController));
            }
        }
    
    private class IncludeBApiControllersInSwagger : IOperationProcessor
        {
            public bool Process(OperationProcessorContext context)
            {
                 return IsControllerInType(context, typeof(BApiController));
            }
        }
    

    最后一步是在您的控制器上构建适当的继承。

    【讨论】:

      猜你喜欢
      • 2019-11-19
      • 2019-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-13
      • 2021-09-11
      相关资源
      最近更新 更多