Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding "Request matched multiple actions resulting in ambiguity" error in ASP.Net Core

I am trying to do something simple and trivial - or at least I thought.

I am trying to write a base class that can be inherited by each micro-service project I spin up. The point of this base class is to test connectivity from HTTP all the way through to SQL. It is NOT enabled in PROD.

This is one of the (simpler) base classes:

public class DevTestControllerBase: ApiControllerBase
{
    public DevTestControllerBase(IHostingEnvironment env, IConfiguration configuration = null, IMediator mediator = null) : base(env, configuration, mediator)
    {
    }


    [HttpGet]
    public IActionResult Get()
    {
        var response = Mediator.Send(new QueryGet());
        return Ok(response.Result);
    }

    [HttpGet("{id}", Name = "Get")]
    public IActionResult Get(Guid id)
    {
        var response = Mediator.Send(new QueryGetById(id));
        return Ok(response.Result);
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody]DevTestModelBinding value)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        var response = await Mediator.Send(new CommandPost(value));
        return Created("Get", new { id = response });
    }

    [HttpPut("{id}")]
    public IActionResult Put(Guid id, [FromBody]DevTestModelBinding value)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        Mediator.Send(new CommandPut(id, value));
        return Ok();
    }

    [HttpDelete("{id}")]
    public IActionResult Delete(Guid id)
    {
        Mediator.Send(new CommandDelete(id));
        return Ok();
    }
}

I was hoping to use it as:

[Produces("application/json")]
[Route("api/DevTest")]
public class DevTestController : DevTestControllerBase
{
    public DevTestController(IHostingEnvironment env, IConfiguration configuration, IMediator mediator) : base(env, configuration, mediator) { }
}

Unfortunately, it produces this error instead:

AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied:

MyNamespace.Providers.WebApi.Features.DevTest.DevTestController.Get (MyNamespace.Providers.WebApi) MyNamespace.Infrastructure.Web.Controllers.DevTestControllerBase.Get (MyNamespace.Infrastructure.Web)

And since I wanted to use Swagger, I am also getting this error when trying to hit the Swagger endpoint:

An unhandled exception has occurred while executing the request System.NotSupportedException: Ambiguous HTTP method for action - MyNamespace.Providers.WebApi.Features.DevTest.DevTestController.Get (MyNamespace.Providers.WebApi). Actions require an explicit HttpMethod binding for Swagger 2.0

like image 496
Keith Barrows Avatar asked Feb 28 '18 17:02

Keith Barrows


1 Answers

Make your base controllers abstract. Otherwise, they participate in routing as possible controllers that can be routed to. Although I'm a little surprised, honestly, that the routing based on controller name convention still works with a class ending in ControllerBase instead of just Controller, it would appear that ASP.NET Core sees them both as named DevTest, and therefore ambiguous.

You could probably alternatively rename the base controller(s) to something like BaseDevTestController (i.e. with "Base" before "Controller"), which would then make the names DevTest and BaseDevTest, removing the abmiguity. However, it's still a better idea to just make it abstract, as it should be anyways. You wouldn't want someone to actually be able to navigate directly to your base controller(s).

like image 115
Chris Pratt Avatar answered Oct 17 '22 01:10

Chris Pratt