动作需要 Swagger 的唯一方法/路径组合
Posted
技术标签:
【中文标题】动作需要 Swagger 的唯一方法/路径组合【英文标题】:Actions require unique method/path combination for Swagger 【发布时间】:2019-06-13 11:53:27 【问题描述】:我在同一个控制器中有 2 个HTTP GET
方法并给我这个错误
HTTP 方法“GET”和路径“api/DataStore”被操作重载 - DPK.HostApi.Controllers.DataStoreController.GetByIdAsync (DPK.HostApi)、DPK.HostApi.Controllers.DataStoreController.GetAllAsync (DPK.HostApi)。操作需要 Swagger 2.0 的唯一方法/路径组合。
我的控制器:
[Route("api/[controller]")]
[ApiController]
public class DataStoreController : ApiControllerBase
private readonly IDataStoreService _dataStoreService;
public DataStoreController(IDataStoreService dataStoreService)
_dataStoreService = dataStoreService;
[HttpPost]
public async Task<IActionResult> PostAsync([FromBody] DataStoreCommand dataStoreCommand)
try
if (ModelState.IsValid)
await _dataStoreService.PostAsync(dataStoreCommand);
return Ok();
var errorList = ModelState.Values.SelectMany(m => m.Errors).Select(e => e.ErrorMessage).ToList();
return ValidationProblem();
catch (Exception e)
Console.WriteLine(e);
throw;
[HttpPut]
public async Task<IActionResult> PutAsync([FromBody] DataStoreCommand dataStoreCommand)
try
if (ModelState.IsValid)
await _dataStoreService.PutAsync(dataStoreCommand);
return Ok();
var errorList = ModelState.Values.SelectMany(m => m.Errors).Select(e => e.ErrorMessage).ToList();
return ValidationProblem();
catch (Exception e)
Console.WriteLine(e);
throw;
[HttpDelete]
public async Task<IActionResult> DeleteAsync(int id)
try
if (ModelState.IsValid)
var item = await _dataStoreService.GetByIdAsync(id);
await _dataStoreService.DeleteAsync(item);
return Ok();
var errorList = ModelState.Values.SelectMany(m => m.Errors).Select(e => e.ErrorMessage).ToList();
return ValidationProblem();
catch (Exception e)
Console.WriteLine(e);
throw;
[HttpGet]
public async Task<DataStoreQuery> GetByIdAsync(int id)
try
return await _dataStoreService.GetByIdAsync(id);
catch (Exception e)
Console.WriteLine(e);
throw;
[HttpGet]
public async Task<IEnumerable<DataStoreQuery>> GetAllAsync(string instanceName, string dbname, string userName, string userPass, bool isActive, DateTime? startCreatedDate, DateTime? endCreatedDate, DateTime? startModifiedDate, DateTime? endModifiedDate)
object[] parameters = instanceName, dbname, userName, userPass, isActive, startCreatedDate, endCreatedDate, startModifiedDate, endModifiedDate;
var parameterName = "@instanceName , @dbname , @userName , @userPass , @isActive , @startCreatedDate , @endCreatedDate , @startModifiedDate , @endModifiedDate";
try
return await _dataStoreService.ExecWithStoreProcedure(parameterName, parameters);
catch (Exception e)
Console.WriteLine(e);
throw;
我的创业:
public class Startup
public Startup(IConfiguration configuration)
Configuration = configuration;
public IConfiguration Configuration get;
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSwaggerGen(c =>
c.SwaggerDoc("v1", new Info
Version = "v1",
Title = " ",
Description = " ",
TermsOfService = "None",
Contact = new Contact() Name = " ", Email = " ", Url = " "
);
);
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUI(c =>
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
);
【问题讨论】:
【参考方案1】:你可以这样解决:
services.AddSwaggerGen (c =>
other configs;
c.ResolveConflictingActions (apiDescriptions => apiDescriptions.First ());
);
//in the Startup.cs class in the ConfigureServices method
或者您可以放置路线来区分您的方法,例如:
[HttpGet("~/getsomething")]
[HttpGet("~/getothersomething")]
【讨论】:
Santos 第一个解决方案意味着只有第一个动作被记录在 Swagger 中。通常,您希望避免未记录的端点...【参考方案2】:我将控制器路由更改为以下:
[Route("api/[controller]/[action]")]
或者您也可以为操作定义明确的路线:
[Route("GetById")]
【讨论】:
由于某种原因,当我使用[Route]
时,我在文档中没有得到api/v1/[controller]/myroute
,我只得到/myroute
,而所有其他HTTP 动词都有完整的api 路径。第一个解决方案是合理的,因为它似乎将方法名称作为终点。【参考方案3】:
您需要将id
映射到HttpGet
。
[HttpGet("id")]
public async Task<DataStoreQuery> GetByIdAsync(int id)
try
return await _dataStoreService.GetByIdAsync(id);
catch (Exception e)
Console.WriteLine(e);
throw;
当您通过不提供模板来指定 HttpGet 时,Swashbuckle 会尝试为它们使用默认映射。因此发生冲突。
【讨论】:
【参考方案4】:您还可以将具有相同端点的方法合并为一个带有可选参数的方法。在 net core 5 项目中测试的实现示例:
services.AddSwaggerGen(c =>
c.ResolveConflictingActions(apiDescriptions =>
var descriptions = apiDescriptions as ApiDescription[] ?? apiDescriptions.ToArray();
var first = descriptions.First(); // build relative to the 1st method
var parameters = descriptions.SelectMany(d => d.ParameterDescriptions).ToList();
first.ParameterDescriptions.Clear();
// add parameters and make them optional
foreach (var parameter in parameters)
if (first.ParameterDescriptions.All(x => x.Name != parameter.Name))
first.ParameterDescriptions.Add(new ApiParameterDescription
ModelMetadata = parameter.ModelMetadata,
Name = parameter.Name,
ParameterDescriptor = parameter.ParameterDescriptor,
Source = parameter.Source,
IsRequired = false,
DefaultValue = null
);
return first;
);
);
【讨论】:
【参考方案5】:如果方法名称相同,则更改请求方法带参数。 我将请求方法更改为以下:
[HttpGet]
public string products()
// add other code
// ex. (return "products()";)
[HttpGet("id")]
public string products(int id)
// add other code
// ex. (return "products(int id)";)
【讨论】:
以上是关于动作需要 Swagger 的唯一方法/路径组合的主要内容,如果未能解决你的问题,请参考以下文章
使用动作约束时在 MVC 6 中使用 Swagger 的多个 Api 版本
动作错误的swagger .net核心API模棱两可的HTTP方法