Shai Cohen
Shai Cohen

Reputation: 6249

Why are these two API methods generating a conflict

We are developing an MVC4 API application and have run across a strange issue that we have no explanation for.

The API controller has two methods:

    [AllowAnonymous]
    [AcceptVerbs("Post", "Get")]
    public ArtifactContent Post(string userName, string password, string id) ...

and

    [AllowAnonymous]
    [AcceptVerbs("Get")]
    public HttpResponseMessage Get(string userName, string password, string id, EnumType contentType) ...

Although the two methods clearly have different method signatures, we are getting the following error message:

{"Message":"An error has occurred.","ExceptionMessage":"Multiple actions were found that match the request: [XXX].Models.ArtifactContent Post(System.String, System.String, System.String) on type [XXX].API.ArtifactContentController\r\nSystem.Net.Http.HttpResponseMessage Get(System.String, System.String, System.String, ArtifactContentTypes) on type [XXX].API.ArtifactContentController","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)"}

We can work around the error by making one of these two changes, but I really want to know why .NET is throwing the error when the two signature are clearly different:

  1. Remove the Get AcceptVerbs attribute from the Post method
  2. Change the signature of the Get method to accept the Enum as an integer

Upvotes: 4

Views: 1255

Answers (1)

Filip W
Filip W

Reputation: 27187

This is a known behavior/issue/bug in ASP.NET Web API.

In short, the action selector (IHttpActionSelector), will not take into account Enums when trying to match the incoming HTTP request to a relevant action inside the controller.

The reason is by default only primitive types (i.e. int, string etc) are picked from RouteData to find a matching action. Enum is not one of those, so it's ignored and therefore, even though your actions have different signatures from the compiler perspective, in the eyes of the action selector they are identical.

You can track the progress of the potential fix here - http://aspnetwebstack.codeplex.com/workitem/312

For the time being, as you said yourself, the best workaround is to pass enum as int or string (and cast to enum).

Upvotes: 5

Related Questions