I just read this post by Dave Ward (http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/), and I'm trying to throw together a simple web api controller that will accept a viewmodel, and something just isn't clicking for me.
I want my viewmodel to be an object with a couple DateTime properties:
public class DateRange
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
Without changing anything in the stock web api project, I edit my values controller to this:
public IEnumerable<float> Get()
{
DateRange range = new DateRange()
{
Start = DateTime.Now.AddDays(-1),
End = DateTime.Now
};
return Repo.Get(range);
}
// GET api/values/5
public IEnumerable<float> Get(DateRange id)
{
return Repo.Get(range);
}
However, when I try to use this controller, I get this error:
Multiple actions were found that match the request:
System.Collections.Generic.IEnumerable1[System.Single] Get() on type FEPIWebService.Controllers.ValuesController
System.Collections.Generic.IEnumerable1[System.Single] Get(FEPIWebService.Models.DateRange) on type FEPIWebService.Controllers.ValuesController
This message appears when I hit
/api/values
or
/api/values?start=01/01/2013&end=02/02/2013
How can I solve the ambiguity between the first and second get actions?
For further credit, if I had this action
public void Post(DateRange value)
{
}
how could I post the Start and End properties to that object using jQuery so that modelbinding would build up the DateRange parameter?
Thanks!
Chris
The answer is in detail described here: Routing and Action Selection. The Extract
With that background, here is the action selection algorithm.
- Create a list of all actions on the controller that match the HTTP request method.
- If the route dictionary has an "action" entry, remove actions whose name does not match this value.
- Try to match action parameters to the URI, as follows:
- For each action, get a list of the parameters that are a simple type, where the binding gets the parameter from the URI. Exclude optional parameters.
- From this list, try to find a match for each parameter name, either in the route dictionary or in the URI query string. Matches are case insensitive and do not depend on the parameter order.
- Select an action where every parameter in the list has a match in the URI.
- If more that one action meets these criteria, pick the one with the most parameter matches.
4.Ignore actions with the [NonAction] attribute.
Other words, The ID parameter you are using, is not SimpleType, so it does not help to decide which of your Get methods to use. Usually the Id is integer or guid..., then both methods could live side by side
If both of them would return IList<float>, solution could be to omit one of them:
public IEnumerable<float> Get([FromUri]DateRange id)
{
range = range ?? new DateRange()
{
Start = DateTime.Now.AddDays(-1),
End = DateTime.Now
};
return Repo.Get(range);
}
And now both will work
/api/values
or
/api/values?Start=2011-01-01&End=2014-01-01
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With