TropicalViking
TropicalViking

Reputation: 435

Swashbuckle crashes by just adding another action method in controller

I have just added another post method in a controller, and the Swagger Swashbuckle crashed. How to solve this ?

 [HttpPost]
        public IActionResult CreateCars(List<Car> cars)
        {
            _carService.CreateCars(cars);
            return NoContent();
        }

System.NotSupportedException: HTTP method "POST" & path "api/Cars" overloaded by actions - IrkcnuApi.Controllers.CarsController.Create (WebApi),MyWebAPI.Controllers.CarsController.CreateCars (MyWebApi). Actions require unique method/path combination for OpenAPI 3.0. Use ConflictingActionsResolver as a workaround
   at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperations(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository)
   at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GeneratePaths(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository)
   at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(String documentName, String host, String basePath)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Upvotes: 3

Views: 6368

Answers (3)

Francesco Rocco
Francesco Rocco

Reputation: 11

In my code i use Swagger Swashbuckle 5.5.1 and Microsoft.AspNetCore.Mvc.Versioning 4.1.1 For me [ApiExplorerSettings(GroupName = "vx.0")] where x is version of multiple action in the same controller or other controller, works fine. I also use MapToApiVersion attribute togheter but the attribute ApiExplorerSettings avoid conflict. See https://www.myget.org/feed/domaindrivendev/package/nuget/Swashbuckle.AspNetCore.Swagger at "Decorate Individual Actions"

In my test i have 2 controllers. First controller maps version 1.0 and 2.0. Second controller map only version 3.0

First controller:

[Authorize]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("viewqlikapi")]
[Route("ViewQlikApi/v{version:apiVersion}")]
[ApiController]
public class QlikController : ControllerBase, IQlikController

And two action that have the same route // Dati Pratica Audit

[HttpGet]
[ApiExplorerSettings(GroupName = "v1.0")]
[Route("datipraticaaudit")]
public RisultatoElementiPagina<ViewQlikDatiPraticaAudit GetElementiPaginaDatiPraticaAudit(int numeroElementi, int indicePagina)....

[HttpGet]
[MapToApiVersion("2.0")]
[ApiExplorerSettings(GroupName = "v2.0")]
[Route("datipraticaaudit")]
public RisultatoElementiPagina<ViewQlikDatiPraticaAudit> GetElementiPaginaDatiPraticaAuditV2(int numeroElementi, int indicePagina, int other)...

and the second controller..

[Authorize]
[ApiVersion("3.0")]
[Route("ViewQlikApi/v{version:apiVersion}")]
[ApiController]
public class QlikV2Controller : ControllerBase

and the action

[HttpGet]
[MapToApiVersion("3.0")]
[ApiExplorerSettings(GroupName = "v3.0")]
[Route("auditoperativoaccesso")]
public RisultatoElementiPagina<ViewQlikAuditOperativoAccesso> GetElementiPaginaAuditOperativoAccesso(int numeroElementi, int indicePagina, int o)

Upvotes: 1

BV Winoya
BV Winoya

Reputation: 345

Use the following code to resolve the issue,

services.AddSwaggerGen(options =>
        {

            options.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
        });

Upvotes: 3

Frederik Gheysels
Frederik Gheysels

Reputation: 56984

You already have a method in your controller that is attributed with a HttpPost attribute. Since you do not explicitly specify a route, these operations clash.

You'll solve this by specifying a route for these POST operations, for instance:

[HttpPost("createMultiple")]
public IActionResult CreateCars(List<Car> cars) {}

[HttpPost()]
public IActionResult CreateCar(Car car) {}

The above suggestion is offcourse not that 'RESTfull', since you have verbs in your URLs.

I'd suggest to modify your code so that you only have one 'Create' method, since the above 2 operations are actually implicitely the same (I guess). Calling the CreateCars operation with a collection of Cars that only contains one item is in a sense actually identical to calling the CreateCar operation.

Upvotes: 5

Related Questions