Actions require unique method/path combination for Swagger
Solution 1
You can resolve it as follows:
services.AddSwaggerGen (c =>
{
other configs;
c.ResolveConflictingActions (apiDescriptions => apiDescriptions.First ());
});
//in the Startup.cs class in the ConfigureServices method
or you can put routes to differentiate your methods, for example:
[HttpGet("~/getsomething")]
[HttpGet("~/getothersomething")]
Solution 2
I changed the controller route to following:
[Route("api/[controller]/[action]")]
or you can also define explicit route for action as well:
[Route("GetById")]
Solution 3
you need to map id
into HttpGet
.
[HttpGet("{id}")]
public async Task<DataStoreQuery> GetByIdAsync(int id)
{
try
{
return await _dataStoreService.GetByIdAsync(id);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
when you specify HttpGet by not providing template, Swashbuckle tries to use default map for both of them. hence conflict occurs.
Solution 4
You can also merge methods with same endpoints to one with optional parameters. Example of implementation tested in net core 5 project:
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;
});
});
Related videos on Youtube
ekad
Updated on July 09, 2022Comments
-
ekad almost 2 years
I have 2
HTTP GET
method in same controller and give me this errorHTTP method "GET" & path "api/DataStore" overloaded by actions - DPK.HostApi.Controllers.DataStoreController.GetByIdAsync (DPK.HostApi),DPK.HostApi.Controllers.DataStoreController.GetAllAsync (DPK.HostApi). Actions require unique method/path combination for Swagger 2.0.
My Controller :
[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; } } }
My Startup :
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"); }); } }
-
Neurion about 4 yearsSantos The first solution would mean only the first action gets documented in Swagger. Generally you want to avoid undocumented endpoints...
-
user1574598 almost 3 yearsFor some reason I don't get
api/v1/[controller]/myroute
in the docs when I use[Route]
, I just get/myroute
whilst all the other HTTP verbs have the full api path. First solution is reasonable though as it seems to pull in the method names as the end points.