C# .Net Core 3.1 swagger API版本控制冲突名称空间url
我正在使用swagger生成API文档,现在我需要对一些端点进行版本设置 所以我配置了swagger来识别我的版本并正确映射端点。但是,由于我在不同的名称空间中使用了相同的类名,所以swagger正在失去它的踪迹,我得到了以下错误:C# .Net Core 3.1 swagger API版本控制冲突名称空间url,c#,.net-core,swagger,swagger-ui,api-versioning,C#,.net Core,Swagger,Swagger Ui,Api Versioning,我正在使用swagger生成API文档,现在我需要对一些端点进行版本设置 所以我配置了swagger来识别我的版本并正确映射端点。但是,由于我在不同的名称空间中使用了相同的类名,所以swagger正在失去它的踪迹,我得到了以下错误: Conflicting method/path combination "GET api/v1/A" for actions - TesteSwagger.Controllers.B.AController.x (TesteSwagger),Te
Conflicting method/path combination "GET api/v1/A" for actions - TesteSwagger.Controllers.B.AController.x (TesteSwagger),TesteSwagger.Controllers.A.AController.x (TesteSwagger). Actions require a unique method/path combination for Swagger/OpenAPI 3.0. Use ConflictingActionsResolver as a workaround
这是我复制的例子
我所有的招摇过市软件包都是6.0.2版
我使用的是.NETCore3.1WebAPI默认的空模板
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddApiVersioning(
options =>
{
options.ReportApiVersions = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
});
services.AddVersionedApiExplorer(
options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddSwaggerGen(options =>
{
options.CustomSchemaIds(x => x.FullName);
options.DescribeAllParametersInCamelCase();
options.OperationFilter<SwaggerDefaultValues>();
options.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger()
.UseSwaggerUI(c =>
{
c.DisplayRequestDuration();
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
description.GroupName.ToUpperInvariant());
}
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
public class SwaggerDefaultValues : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
}
}
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
public void Configure(SwaggerGenOptions options)
{
}
}
namespace TesteSwagger.Controllers.A
{
[ApiController, ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class AController : ControllerBase
{
[HttpPost]
[ProducesResponseType(typeof(B), (int)HttpStatusCode.OK)]
public IActionResult x(A a) => Ok(new B());
}
public class A
{
public int Foo { get; set; }
}
public class B
{
public int Bar { get; set; }
}
}
namespace TesteSwagger.Controllers.B
{
[ApiController, ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class AController : ControllerBase
{
[HttpPost]
[ProducesResponseType(typeof(B), (int)HttpStatusCode.OK)]
public IActionResult x(A a) => Ok(new B());
}
public class A
{
public int Foo { get; set; }
}
public class B
{
public int Bar { get; set; }
}
}
B控制器(v2):
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddApiVersioning(
options =>
{
options.ReportApiVersions = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
});
services.AddVersionedApiExplorer(
options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddSwaggerGen(options =>
{
options.CustomSchemaIds(x => x.FullName);
options.DescribeAllParametersInCamelCase();
options.OperationFilter<SwaggerDefaultValues>();
options.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger()
.UseSwaggerUI(c =>
{
c.DisplayRequestDuration();
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
description.GroupName.ToUpperInvariant());
}
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
public class SwaggerDefaultValues : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
}
}
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
public void Configure(SwaggerGenOptions options)
{
}
}
namespace TesteSwagger.Controllers.A
{
[ApiController, ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class AController : ControllerBase
{
[HttpPost]
[ProducesResponseType(typeof(B), (int)HttpStatusCode.OK)]
public IActionResult x(A a) => Ok(new B());
}
public class A
{
public int Foo { get; set; }
}
public class B
{
public int Bar { get; set; }
}
}
namespace TesteSwagger.Controllers.B
{
[ApiController, ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class AController : ControllerBase
{
[HttpPost]
[ProducesResponseType(typeof(B), (int)HttpStatusCode.OK)]
public IActionResult x(A a) => Ok(new B());
}
public class A
{
public int Foo { get; set; }
}
public class B
{
public int Bar { get; set; }
}
}
swagger的v1 URL加载得很好,只有当我将其更改为v2时,屏幕上才会显示此错误:
Fetch error
undefined /swagger/v2/swagger.json
我使用v1url上生成的curl进行测试,一切正常,只是大摇大摆不明白
// works great
curl -X POST "https://localhost:44312/api/v1/A" -H "accept: text/plain" -H "Content-Type: application/json" -d "{\"foo\":0}"
// works great
curl -X POST "https://localhost:44312/api/v2/A" -H "accept: text/plain" -H "Content-Type: application/json" -d "{\"foo\":0}"
我真的不知道我是否做错了什么或大摇大摆真的不支持这种版本控制
有什么想法吗?首先,类型的名称在很大程度上是不相关的。名称空间不是一个通常可以通过HTTP传输的概念,它高度依赖于媒体类型。现代JavaScript确实有模块,但它不是一个完全的名称空间。无论如何,.NET名称空间不会转换为一组JavaScript模块,以JSON表示;当然,不是默认的 这里的系统性问题似乎是您定义了一个虚张声势的配置,而没有任何实际的配置。三件事必须排成一行,才能让所有的部分走到一起:
apiscription.GroupName
整理成组。当按URL段进行版本控制时,AddVersionedApiExplorer
中的配置有助于将其与典型的Swashback格式和示例对齐使用招摇过市界面
。每个API版本预期有一个端点。段值通常映射到API版本组名称(例如格式化版本)apiscription.GroupName
和#2中定义的端点段public void配置(招摇过市选项)
{
//配置Swashback以根据定义的API版本定义一个Swagger文档
foreach(provider.ApiVersionDescriptions中的变量描述)
{
options.SwaggerDoc(
description.GroupName,
新openapinfo()
{
Title=“API”+description.GroupName,
Version=description.apivision.ToString(),
} );
}
}
我认为您有一个名称空间TesteSwagger.Controllers.B和一个令人困惑的类B。错误消息说,我没有使用ProducesResponseType(typeof(B))try ProducesResponseType(typeof(TesteSwagger.Controllers.B.B))不工作,而是完全限定了两个控制器中的参数和响应,仍然存在相同的问题。错误消息指出需要使用全名(包括命名空间)。尚不清楚需要更改哪些对象。我只是猜是B班。Th3可能还有其他类似的对象也需要更改。没有其他对象,这是一个仅为模拟错误而创建的干净项目,这是我的解决方案中仅有的两个对象和唯一的控制器您是否尝试过“x(a a)=>Ok(new B())”的全名?我不知道swagger是如何将字符串名转换为类类型的,但很明显,它不喜欢以句点后跟“B”的名称空间。