Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebApi 'Multiple actions were found that match the request' error after making call in angular

I feel I have the routes, controller and the call correct, but still cannot figure out why I am getting the 'Multiple actions' error. The controller itself makes call to a service bus, but I cannot get it to hit my breakpoint for GetJob. Any ideas?

Route:

public class WebApiInitializer : IInitializableModule
    {
        public void Initialize(InitializationEngine context)
        {    
            RouteTable.Routes.MapHttpRoute(
                "webapimethodroutes",
                "api/msi/{controller}/{action}",
                defaults: new {}
                );
        }
    }

My Job Controller:

public class SBJobController : ApiController, IJobsController
    {
        [HttpPost]
        public CreateJobResponse CreateJob(CreateJobRequest request)
        {
            return BusProxy.Call<CreateJobRequest, CreateJobResponse>(request);
        }

        [HttpPost]
        public GetJobResponse GetJob(GetJobRequest request)
        {
            return BusProxy.Call<GetJobRequest, GetJobResponse>(request);
        }
    }

My service call in angular:

function getJobs(pRequest) {
            var request = pRequest || {
                'Ids': [],
                'JobNumbers': [],
                'PageNumber': 1,
                'PageSize': 20,
            };
            return $http.post('/api/msi/SBJob/GetJob', request).error(function (data, status, headers, config) {
                //logError(data);
            });
        }

The request objects:

public class CreateJobRequest : RequestBase
    {
        public JobEntity Job { get; set; }
        public AddressEntity Address { set; get; }
    }

public class GetJobRequest: RequestBase, IPageable
    {
        public int PageNumber { set; get; }
        public int PageSize { set; get; }
        public List<Guid> Ids { set; get; }
        public List<string> JobNumbers { set; get; }
        public Guid ChildOfCustomer { set; get; }
        public Guid ChildOfContact { set; get; }
        public JobTypeEnum JobType { get; set; }
    }

The exact error I am getting:

{
    "Message": "An error has occurred.",
    "ExceptionMessage": "Multiple actions were found that match the request: \r\nCreateJob on type MSI.ServiceBus.ServiceControllers.SBJobController\r\nGetJob on type MSI.ServiceBus.ServiceControllers.SBJobController",
    "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.<SendAsync>d__1.MoveNext()"
}
like image 609
sanghas26 Avatar asked Aug 05 '14 17:08

sanghas26


2 Answers

The routing on web api works on this way

  • To find the controller, Web API adds "Controller" to the value of the {controller} variable.

  • To find the action, Web API looks at the HTTP method, and then looks for an action whose name begins with that HTTP method name. For example, with a GET request, Web API looks for an action that starts with "Get...", such as "GetContact" or "GetAllContacts". This convention applies only to GET, POST, PUT, and DELETE methods. You can enable other HTTP methods by using attributes on your controller. We’ll see an example of that later. Other placeholder variables in the route template, such as {id}, are mapped to action parameters.

  • Instead of using the naming convention for HTTP methods, you can explicitly specify the HTTP method for an action by decorating the action method with the HttpGet, HttpPut, HttpPost, or HttpDelete attribute.

That's why is matching 2 actions, the name of the method is not used "by default" to match an action. You may have something like this to make it work

public class WebApiInitializer : IInitializableModule
{
    public void Initialize(InitializationEngine context)
    {    
        RouteTable.Routes.MapHttpRoute(
            "CreateJob",
            "api/msi/SBJob/CreateJob",
            defaults: new {Controller = "SBKob", Action = "CreateJob"}
            );

        RouteTable.Routes.MapHttpRoute(
            "GetJob",
            "api/msi/SBJob/GetJob",
            defaults: new {Controller = "SBKob", Action = "GetJob"}
            );              
    }
}
like image 186
Claudio Redi Avatar answered Sep 19 '22 13:09

Claudio Redi


why not be RESTful with your controller instead of having two Posts, when its really a Get?

    public CreateJobResponse Post(CreateJobRequest request)
    {
        return BusProxy.Call<CreateJobRequest, CreateJobResponse>(request);
    }

    public GetJobResponse Get(int id)
    {
        return BusProxy.Call<GetJobRequest, GetJobResponse>(id);
    }
like image 32
Shane Avatar answered Sep 18 '22 13:09

Shane