69

I have 2 HTTP GET method in same controller and give me this error

HTTP 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"); }); } } 

10 Answers 10

80

I changed the controller route to following:

[Route("api/[controller]/[action]")] 

or you can also define explicit route for action as well:

[Route("GetById")] 
Sign up to request clarification or add additional context in comments.

3 Comments

For 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.
thnx. saved my life
Simply using: '[Route("api/[controller]/[action]")]' works perfectly
62

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")] 

1 Comment

Santos The first solution would mean only the first action gets documented in Swagger. Generally you want to avoid undocumented endpoints...
20

If method has "Name" in it, then also it throws this error. To fix it,

Change from

[HttpGet(Name = "GetWeatherForecast")] [HttpGet(Name = "GetWeatherForecastById")] 

To

[HttpGet("GetWeatherForecast")] [HttpGet("GetWeatherForecastById")] 

3 Comments

Be Careful with this solution because you are changing the route by using it from for example "api/Forecast" to "api/Forecast/GetWeatherForecast" and "api/Forecast/GetWeatherForecastById" for GET methods
this was the problem how annoying @KRM thank you
@user1579019 What's the better way to do this while still being able to have multiple ways to get the data? Is it better to have two separate classes with one output each?
12

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.

Comments

6

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; }); }); 

Comments

5

If the method name are same then change the request method with parameter. I changed the request method to following :

[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)";) } 

Comments

2

None of the other answers worked for me. I spent hours identifying the issue by creating a minimal working sample from the sample code at https://github.com/OData/AspNetCoreOData . It turns out that your id parameter must be called "key" for this to work.

This controller code produces the error you mention:

[HttpGet] [EnableQuery] public IActionResult Get(CancellationToken cancellationToken) [...] [EnableQuery] [HttpGet] public IActionResult Get(Guid id) [...] 

This works:

[HttpGet] [EnableQuery] public IActionResult Get(CancellationToken cancellationToken) [...] [EnableQuery] [HttpGet] public IActionResult Get(Guid key) [...] 

The only difference here is the name of the Guid parameter.

I assume this requirement is some non-obvious (to me) OData/Swagger convention. Please comment or edit my answer if you know more.

1 Comment

What is EnableQueryAttribute?
1

This is how I specified the unique routes for method name

[HttpGet("~/GetWeatherForecast")] 

Keeping it above the methods

[HttpGet("~/GetWeatherForecast")] public int Get() { return Random.Next(5) } [HttpPost("~/InsertAddition")] public int InsertAddition(int num1, int num2) { return num1 + num2; } 

Comments

1

You can also ignore obsolete methods

 services.AddSwaggerGen(swaggerGenOptions => { swaggerGenOptions.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); swaggerGenOptions.IgnoreObsoleteActions(); swaggerGenOptions.IgnoreObsoleteProperties(); swaggerGenOptions.CustomSchemaIds(type => type.FullName); } 

Comments

0

Try adding both Route and HttpGet.

 [HttpGet] [Route(~/GetByIdAsync/{id})] public async Task<DataStoreQuery> GetByIdAsync(int id) [HttpGet] [Route(~/GetAllAsync)] public async Task<IEnumerable<DataStoreQuery>> GetAllAsync(string instanceName, string dbname, string userName, string userPass, bool isActive, DateTime? startCreatedDate, DateTime? endCreatedDate, DateTime? startModifiedDate, DateTime? endModifiedDate) 

Comments