drewwyatt
drewwyatt

Reputation: 6027

No action was found that matches the request URI

I have attempted to modify one of my api controller to allow for the creation of multiple reservations by allowing one of the parameters to be passed in as a pipe delimited string. The method and class can be seen here:

public class ReservationsController : ApiController
{
    public HttpResponseMessage PostReservation(string eRaiderUserName, string SpaceNumbers)
    {
        char[] delimiter = { '|' };
        string[] spaces = SpaceNumbers.Split(delimiter);
        bool saved = true;
        foreach(string space in spaces)
        {
            var reservation = new Reservation { eRaiderUserName=eRaiderUserName, SpaceNumber=Convert.ToInt32(space) };
            if (true)
            {
                reservation.Game = db.Games.FirstOrDefault(g => g.ID == AppSettings.CurrentGameID);
                db.Reservations.Add(reservation);
                db.SaveChanges();

                //HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, reservation);
                //response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = reservation.ID }));
                //return response;
            }
            else
            {
                saved = false;
                //return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }

        db.SaveChanges();
        if (saved)
        {
            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created);
            response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = 1 }));
            return response;
        } else
        {
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        }
    }
}

I have a form that posts what I think should be the right information, but I keep getting this error:

{"$id":"1","Message":"No HTTP resource was found that matches the request URI 'http://localhost:58463/api/Reservations'.","MessageDetail":"No action was found on the controller 'Reservations' that matches the request."}

The (modified) save method in the api is still definitely a work in progress. But what is keeping this from finding the web api controller? Here is the firebug output:

enter image description here

Upvotes: 2

Views: 2824

Answers (3)

JotaBe
JotaBe

Reputation: 39004

As pointed out, the problem is that a POST action can only transfer the data posted in the body to a single object (for technical reasons).

That means that you can get data from the route data, from the querystring, and from the body, with the following limitations:

  • data from querystring or route data must be single values (i.e. they cannnot be classes), in any number
  • you can have only one parameter of the action with data coming from the request body, but this can be a complex class
  • you can make any combination of this, i.e. a single or complex param coming from the body, and any number of single parameters coming from the route data or the querystring.

So, the most generic way to solve your problem (i.e. that can be easyly applied to other classes where you need to pass complex data, even more complex than this case) is this:

First, make a class which has properties for all the needed data,in your case:

public class ReservationData
{
  public string eRaiderUserName { get; set; }
  public string SpaceNumbers  { get; set; }
}

Second, use this class as the type of the received parameter in your action:

public HttpResponseMessage PostReservation(ReservationData reservationData)

With this code the formatter can map all the data in the request body to a single parameter in the action. You can use JSON or formdata formats, like the generated by jQuery.

NOTE: the property names must case-sensitively match the name of the posted parameters.

Upvotes: 6

Muthu R
Muthu R

Reputation: 806

Web API has limited support to map POST form variables to simple parameters of a Web API method. Web API does not deal with multiple posted content values, you can only post a single content value to a Web API Action method.

public HttpResponseMessage PostReservation(string eRaiderUserName, string SpaceNumbers)

{ //...}

and you are trying to call using jQuery:

$.ajax({  url: 'api/reservations', type: 'POST', data: { ... }, dataType: 'json', success: function (data) {alert(data);} }); 

Unfortunately, Web API can’t handle this request and you’ll get error. But if you pass parameters using query string, It’ll work:

$.ajax({ url: 'api/reservations?eRaiderUserName=2012&SpaceNumbers=test', type: 'POST', dataType: 'json', success: function (data) { alert(data); } });

But it’s not good solution and not applicable for complex objects. So here are the different ways to do it.

  1. Using Model Binding (Preferred)
  2. Using Custom Parameter Binding
  3. FormDataCollection
  4. Query String

Upvotes: 0

kolesso
kolesso

Reputation: 336

This is because you send x-www-form-urlencoded data to controller, to handle this data you must use [FromBody] before parameter like

public HttpResponseMessage Post([FromBody] string name) { ... }

but this approach has a lot of limitation: 1) There can be only one parameter marked [FromBody] attribute (it can be complex type) 2) The data must be encoded as =value not as key=value . You can read it here description and how make it work here example . If it possible i recommend you to send Json data to controller, without this limitation.

Upvotes: 1

Related Questions