.net core .Net core 2.2 API版本控制和正确路由

.net core .Net core 2.2 API版本控制和正确路由,.net-core,routes,swagger,versioning,swashbuckle,.net Core,Routes,Swagger,Versioning,Swashbuckle,我正在创建一个API。我使用swagger,但由于有大量的控制器和操作,我想按域划分API端点。为此,我考虑了API的版本控制。我考虑过使用ApiVersion的状态。我的控制器代码如下 [ApiVersion("1.0-First")] //This is ApiVersion MajorVersion = 1, Status = "First" [Route("api/v{version:apiVersion}/[controller]&qu

我正在创建一个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部分的定义也很好。(我知道path应该没有大写字母-这仅用于测试目的)

但昂首阔步无法到达任何终点。因为有效端点位于/api/v1.0-First/First而不是/api/v1/First。
我的startUp类如下所示:

 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);
    }
public void配置服务(IServiceCollection服务)
{
services.AddMvcCore().AddApiExplorer();
services.addapVersioning(c=>
{
c、 ApiVersionReader=ApiVersionReader.Combine(
新QueryStringApersionReader(“V”),
新的URLSectionApiversionReader());
c、 ReportApiVersions=false;
c、 DefaultApiVersion=新的ApiVersion(1,0);
});
services.AddVersionedApiExplorer(选项=>
{
options.substituteApprovisionInUrl=true;
options.SubstitutionFormat=“V”;
options.DefaultApiVersion=新的ApiVersion(1,0);
});
services.RegisterSwagerConfiguration();
}
公共无效配置(IApplicationBuilder应用程序,IHostingEnvironment环境)
{
app.UseDeveloperExceptionPage();
app.UseHttpsRedirection();
app.UseMvc();
app.AddSwagger(app.ApplicationServices.GetService(),配置);
}
我编写了一些静态类来添加基于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);
            }
        });
    }
}
公共静态类扩展
{
公共静态无效注册表WaggerConfiguration(此IServiceCollection服务)
{
services.AddTransient();
services.addswagggen();
}
公共静态void AddSwagger(此IAApplicationBuilder应用程序、IApiVersionDescriptionProvider提供程序、IConfiguration配置)
{
var prefix=“招摇过市”;
app.UseSwagger();
app.UseSwaggerUI(c=>
{
c、 RoutePrefix=string.Empty;
foreach(provider.ApiVersionDescriptions中的变量描述)
{
c、 swagger端点($“{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;
    }
}
public类配置swagger选项:IConfigureOptions
{
私有只读IApiVersionDescriptionProvider;
专用只读IConfiguration配置;
公共配置Swagger选项(IApiVersionDescriptionProvider提供程序、IConfiguration配置)
{
this.provider=提供者;
this.configuration=配置;
}
公共void配置(招摇过市选项)
{
foreach(provider.ApiVersionDescriptions中的变量描述)
{
options.SwaggerDoc(description.GroupName,CreateInfoForApiVersion(description));
}
}
私有OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription描述)
{
var info=new openapinfo()
{
Title=description.GroupName,
Version=description.apivision.ToString(),
};
如果(说明已说明)
{
info.Description+=“此API版本已被弃用。”;
}
退货信息;
}
}
我希望以api/v1/First或api/v1.0/First的形式获得路由工作(这应该无关紧要)。
也许编写一些自定义中间件来处理这种情况是个好主意?
到目前为止,我已经没有想法了,一般来说,我找不到任何关于ApiVersion使用状态的文章。
编辑:
更改了标题。

不久前我们遇到了类似的问题。我们需要按客户权限/域划分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));
        }
    }
最后一步是在控制器上构建适当的继承