简体   繁体   中英

Why does ASP.NET Web Api model binding uses the parameter type to determine the source of the value?

Since a few days I'm trying to create my own web api controller. Duo to the rest conventions I need to use a post request to create an object. To get concrete, Im having this controller with this action:

public class ReservationController : ApiController
{
    [HttpPost]
    public void Create(int roomId, DateTime arrivalDate)
    {
      //do something with both parameters   
    }
}

This code is not working when I fire a post request at it, I'm receiving a 404 exception something like this:

No action was found on the controller 'Some' that matches the request.

The reason for it is that simple types are read from the query string, complex types from the body, according to this aricle . The web api uses the parameters to match the action to a request and can't therefore map my action to the request.

I do know that I can use the [frombody] tag, but you can only apply that to one parameter and I have 2. I also know that I can create a wrapper object which have both the parameters, but I'm not willing to use wrappers for all my calls.

So I do know that I can work around this by these methods. I also think that this is caused by the fact that the body of the post request can only be read once. But my actual question is:

Why is the source of a parameter determined by it's type and not by it's availability, especially when the conventions state that you should make for example a post request for creation? In MVC this is the case, why isn't it in the web api?

Best regards,

BHD

FINAL UPDATE Since I'm getting some upvotes, problably more people are facing the same question. In the end it comes to this: Web-Api != MVC. It's simply not the same thing and the web api team made different design decisions than the mvc team I guess.

It seems that you have a fundamental misunderstanding of how Web API actually works.

Web API routing is driven off of verbiage, not the method names. "SomeMethod" actually translates to zero useful information for Web API. As a result, if I post

api/some/some?id=1

OR

api/some/somemethod?id=1

OR EVEN

api/some/?id=1

and the SomeMethod endpoint is the ONLY available POST, it will hit that endpoint.

As such, first of all, make sure you have only one POST on that api controller. If you do, POSTing to it from any test client using either of the query strings above will work just fine.

You can use the [FromBody] attribute on the parameter to force it to read from the body of the HTTP POST instead of the Uri. This is opposed to the [FromUri] attribute which does the opposite.

[HttpPost]
public void SomeAction([FromBody] int id)
{
    //do something with id    
}

Are you sure you're actually putting the id in the body? It could also be a routing issue. If this still doesn't work then maybe you should use Fiddler and copy the RAW output of your HTTP message here.

If you're packing multiple values into the body such as with JSON then you should use a model which should automatically be deserialized to:

public class PostModel
{
    public int ID { get; set; }
    public int SomeOtherID { get; set; }
}

[HttpPost]
public void SomeAction(PostModel postModel)
{
    //do something with postModel.ID and postModel.SomeOtherID
}

You can actually do this straight out of the box in WebAPI, at least in 2.2 (.Net version 4.5.2). Your controller is correct. Using your controller, if you call it with a HTTP POST like this (tested through Fiddler):

http://localhost:58397/api/Reservation?roomId=123&arrivalDate=2015-12-17

You'll get the correct values of roomId = 123 and arrivalDate = 17.12.2015.

I suspect there's something wrong in your call to the WebAPI. Maybe post that call if you're still not getting it to work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM