Using the standard route:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
With these actions:
public class ValuesController : ApiController
{
// GET api/values
public string GetAll()
{
return "all";
}
// GET api/values/5
public string GetById(int id)
{
return "single";
}
// GET api/values?ids=1&ids=2
public string GetByIds([FromUri] int[] ids)
{
return "multiple";
}
And make a request to /api/values, I get this exception:
Multiple actions were found that match the request:
System.String GetAll() on type MvcApplication4.Controllers.ValuesController
System.String GetByIds(Int32[]) on type MvcApplication4.Controllers.ValuesController
I've been spinning my wheels trying to find a solution around this. It's my belief that the GetAll and GetByIds actions are considered Multiple here, but they aren't because the GetByIds has a different signature.
Is there a work around for this that doesn't involve adding {action}
to the route?
As mentioned, Web API controller can include multiple Get methods with different parameters and types. Let's add following action methods in StudentController to demonstrate how Web API handles multiple HTTP GET requests.
Routing is how Web API matches a URI to an action. Web API 2 supports a new type of routing, called attribute routing. As the name implies, attribute routing uses attributes to define routes. Attribute routing gives you more control over the URIs in your web API.
Thanks for the input everyone. After kicking options around, the only way I found to do this, is to combine the GetAll and GetByIds action and switch case the length of ids.
public class ValuesController : ApiController
{
// GET api/values/5
public string GetById(int id)
{
return "single";
}
// GET api/values
// GET api/values?ids=1&ids=2
public string GetByIds([FromUri] int[] ids)
{
switch (ids.Length)
{
case 0:
return "all";
default:
return "multiple";
}
}
We currently do not have out of box support for binding collection of values coming from Uri. Following is the issue regarding that and also the action disambiguation problem:
http://aspnetwebstack.codeplex.com/workitem/322
Unfortunately, i cannot think of a work around related to the Action selection problem(without the '{action}') itself even though you solve the problem of modelbinding to collection using a custom parameter binding like below:
public string GetByIds(int[] ids)
{
return "multiple";
}
------------------------
config.ParameterBindingRules.Insert(0, typeof(int[]), (paramDesc) => new SampleParameterBinding(paramDesc));
-------------------------
public class SampleParameterBinding : HttpParameterBinding
{
public SampleParameterBinding(HttpParameterDescriptor desc)
: base(desc)
{
}
public override bool WillReadBody
{
get
{
return false;
}
}
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
{
HttpRequestMessage currentRequest = actionContext.Request;
NameValueCollection nvc = currentRequest.RequestUri.ParseQueryString();
//TODO: ERROR CHECKS
int[] ids = nvc["ids"].Split(',').Select(str => Int32.Parse(str)).ToArray();
// Set the binding result here
SetValue(actionContext, ids);
// now, we can return a completed task with no result
TaskCompletionSource<AsyncVoid> tcs = new TaskCompletionSource<AsyncVoid>();
tcs.SetResult(default(AsyncVoid));
return tcs.Task;
}
private struct AsyncVoid
{
}
}
I'd recommend attribute routing:
[RoutePrefix("api")]
public class ValuesController : ApiController
{
// GET api/values
// GET api/values?ids=1&ids=2
[Route("values")]
public string GetCollection([FromUri] IList<int> ids)
{
if (ids == null)
{
return "all";
}
return "multiple";
}
// GET api/values/5
[Route("values/{id:int}")]
public string GetById(int id)
{
return "single";
}
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