Reputation: 2685
Suppose I have a very simple routing table, like this:
routes.MapHttpRoute("root", "",
new { controller = "Home", action = "Index" });
And within my HomeController
, I have two methods called Index
:
[HttpGet]
public IHttpActionResult Index()
{
return Content(HttpStatusCode.OK, new { service = "hard-coded string" });
}
[HttpGet]
public IHttpActionResult Index(string a)
{
return Content(HttpStatusCode.OK, new { a });
}
If I run this application, routing occurs as I would expect: if I omit the a
parameter from the query string, my request gets routed to the first method, and if I include it, the request is routed to the second method.
However, if I change the type of a
to a more complex type, such as string[]
, then when I make a request on the default route, I get the following error (regardless of whether I specified the query parameter):
{
Message: "An error has occurred."
ExceptionMessage: "Multiple actions were found that match the request: Index on type SurveysApi.v1.Web.Controllers.HomeController Index on type SurveysApi.v1.Web.Controllers.HomeController"
ExceptionType: "System.InvalidOperationException"
StackTrace: " at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext) at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()"
}
The error remains if even if I specify FromUri
or ModelBinder
attributes on the parameter.
Why does this error occur for complex types, and is there any way to avoid it, short of specifying a simple type in the argument list and performing the necessary conversions in the controller method?
Upvotes: 2
Views: 1795
Reputation: 745
Method overloading doesn't seem to play well with Web API. What I suggest you use instead is attribute routing.
Enable it in WebApiConfig.cs
config.MapHttpAttributeRoutes();
An example Controller would be:
public class HomeController : ApiController
{
[Route("home/id/{Id}")]
[HttpGet]
public string Get(int Id)
{
return "id";
}
[Route("home/string/{str}")]
[HttpGet]
public string Get(string str)
{
return "string";
}
}
Method names are the same, but routes are the key factor. Another way you could do this is using the ActionName attribute:
An example Controller would be:
public class HomeController : ApiController
{
[ActionName("GetById")]
public string Get(int id)
{
return "id";
}
[ActionName("GetByGUID")]
public string Get(string id)
{
return "guid";
}
}
Routes would be something like:
//Matches /api/Home/7
config.Routes.MapHttpRoute(
name: "DefaultDigitApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GetById" },
constraints: new { id = @"^\d+$" } // id must be digits
);
//Matches /api/Home/CD73FAD2-E226-4715-B6FA-14EDF0764162
config.Routes.MapHttpRoute(
name: "DefaultGuidApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GetByGUID" },
constraints: new { id = @"\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b" } // id must be guid
);
Hope this helps at least a bit.
Upvotes: 1