Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two HTTP Post method with different parameters in one Web API controller

I'm trying to implement a Controller with more than one POST method in one controller. I have the following:

public class PatientController : ApiController
{
    [HttpGet]
    public IEnumerable<Patient> All() { ... }

    [HttpGet]
    public Patient ByIndex(int index) { ... }

    [HttpPost]
    public HttpResponseMessage Add([FromBody]Patient patient) { ... }
}

And i have a this on my routing:

GlobalConfiguration.Configuration.Routes.MapHttpRoute(
    "API_1",
    "{controller}/{index}",
    new { index = RouteParameter.Optional });

Everything works as expected :)

Now, i would like to add the following action:

    [HttpPost, ActionName("save")]
    public void Save(int not_used = -1) { ... }

Without adding anything to routing, i get the following error in to Fiddler: Multiple actions were found that match the request.

If i add this to my routing (as a second or first, doesn't matter):

GlobalConfiguration.Configuration.Routes.MapHttpRoute(
    "API_2",
    "{controller}/{action}/{not_used}",
    new { not_used = RouteParameter.Optional },
    new { action = "save|reset" }); // Action must be either save or reset

Ill get the same error in to Fiddler.

Is this even possible? Can i have more than one POST, with different (type) parameters, in one controller?

like image 891
KiLa Avatar asked Nov 04 '22 04:11

KiLa


1 Answers

Your problem is that you have two methods: Save and Add, and both match your route API_1. The fact that you have another route API_2 that could have matched if the url had been a little different doesn't matter: you have two matching methods for this route.

You've got a few options:

  1. Put the save method in a different controller, and for that controller always map action names.
  2. Ensure that Save doesn't match the default route. In particular, you've included an optional parameter in Save and that means it's OK to omit. If the parameter were non-optional, it wouldn't match the route.
  3. Change your architecture to use a message-based format; i.e. rather than distinguishing based on actions, simply pass one class and distinguish based on how that's been set (a little unusual in web api, but that's what ServiceStack does
  4. Change your routing to always include the action name.

I can't really say what's best without understanding your exact scenario better; Though personally I'd avoid the trickiness of getting all those arguments and simultaneous routes working on multiple actions - either always be explicit about the action, or address any possible message in code (i.e. options 3 or 4). Complex routes in the face of optional arguments are simply a pain.

like image 137
Eamon Nerbonne Avatar answered Nov 12 '22 17:11

Eamon Nerbonne