locked
Web Api with Multiple Post in one Controller RRS feed

  • Question

  • User-1367372477 posted

    Hi All,

    I have 2 post method in 1 controller.

    [HttpPost]
    public string Hello(string msg)
    {
       return msg;
    }
    [HttpPost]
    public string HelloAgain(string msg)
    {
       return msg;
    }

    I have this error, when trying to call the api "Multiple actions were found that match the request", Can anyone tell me how to solved this one

    /api/Msg/Hello

    Tuesday, June 19, 2012 8:56 AM

Answers

  • User-1153996692 posted

    Yes -- if you want to support action-based routing (that is, the action name is part of the URI), then you need to update your route to:

    "api/{controller}/{action}/{id}"

     

    - Mike

     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, June 21, 2012 2:07 PM

All replies

  • User1779161005 posted

    Don't put two POST methods in one controller :)

    Think about your HTTP request -- how will the runtime (with the default routes) distinguish which action method to invoke? Routing (and thus the URL) does not contain the action name. If you want this, then define a custom route with the action name in the URL, but that goes somewhat counter to the design of WebAPI and action method mapping based upon the HTTP method.

    Tuesday, June 19, 2012 9:12 AM
  • User2040953529 posted

    If you want this, then define a custom route with the action name in the URL, but that goes somewhat counter to the design of WebAPI and action method mapping based upon the HTTP method.

    You're right that the Web API project templates steer you down the route of RESTful controllers... but I'm not sure there is anything wrong per se with writing more RPC style APIs. Sometimes its the right thing to do.

    Tuesday, June 19, 2012 9:56 AM
  • User1779161005 posted

    You're right that the Web API project templates steer you down the route of RESTful controllers... but I'm not sure there is anything wrong per se with writing more RPC style APIs. Sometimes its the right thing to do.

    Well, I don't want to get into a philosophical debate on how to use the framework. I was simply pointing out that the way the plumbing works by default is to prefer only one of each HTTP method per API controller. You can circumvent this by augmenting the routing table.

    Tuesday, June 19, 2012 10:42 AM
  • User-1153996692 posted

    It depends what you want your URIs to look like.

    If you want these URIs:

    /api/Msg/Hello

    /api/Msg/HelloAgain

    ... then you are including the action name in the URI, so you need to include {action} in your route template:

    "api/{controller}/{action}/{id}"

    See http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

    - Mike

    Tuesday, June 19, 2012 11:43 AM
  • User-1367372477 posted

    Hi Mike,

    I have been follow all the way others ppl tutorial but it's get stuck.

    RouteConfig

            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
                routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                routes.MapRoute(
                    name: "Default",
                    url: "{controller}/{action}/{id}",
                    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
                );
            }

    Controller

        public class ValuesController : ApiController
        {
            public Msg Hello(Msg model)
            {
                return model;
            }
            public Msg HelloAgain(Msg model)
            {
                return model;
            }
        }
    
        public class Msg
        {
            public string msgContent { get; set; }
        }

    Fiddler Post it's return me this 

    "Multiple actions were found that match the request: \r\nTest.Controllers.Msg Hello(Test.Controllers.Msg) on type Test.Controllers.ValuesController\r\nTest.Controllers.Msg HelloAgain(Test.Controllers.Msg) on type Test.Controllers.ValuesController"





    Thursday, June 21, 2012 9:37 AM
  • User-1153996692 posted

    Yes -- if you want to support action-based routing (that is, the action name is part of the URI), then you need to update your route to:

    "api/{controller}/{action}/{id}"

     

    - Mike

     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, June 21, 2012 2:07 PM
  • User1850575723 posted

    Hi,

    I have a similar situation.

    My Users Controller:

     public User GetUser(int id)  {

                return repository.GetUserByUserID(id);        

    }    

    public User GetUser(string email) {

                return repository.GetUserByEmail(email);        

    }

     [ActionName("privileges")]        

     public IEnumerable<Privilege> GetPrivileges(int userID) {            

    return repository.GetPrivilegesByUserID(userID);        

     }

     [ActionName("roles")]      

     public IEnumerable<Rol> GetRoles(int userID) {            

     return repository.GetRolesByUserID(userID);        

     }

     

    As you can see I added AcctionName to GetPrivileges and GetRoles, i have 4 URI calls:

    1. http://localhost/MySite/api/users/1 WORKS FINE.

    2. http://localhost/MySite/api/users?email=myemail@mail.com WORKSFINE

    3. http://localhost/MySite/api/users/privileges?userID=1 FAILS: Multiple actions were found that match the request

    4. http://localhost/MySite/api/users/roles?userID=1 FAILS: Multiple actions were found that match the request

    Notice that last 2 calls refers to the actions Privileges and Roles

    My routes on WebApiConfig:

    config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );

    config.Routes.MapHttpRoute( name: "ActionApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } );

    What am I doing wrong?

    Why 3 and 4 fails?

    I'll apreciate your help

     

     

    Monday, February 25, 2013 10:27 AM
  • User2040953529 posted

    Your example URIs are both matching each other. Look more carefully at the rule. The query string is not part of the route. They are matching api/{controller}/{id} with a controller of users and id's of "privileges" and "roles".

     

    To see this try http://localhost/MySite/api/users/privileges/1 - that should match your action route.

    Monday, February 25, 2013 2:41 PM
  • User1850575723 posted

    James,

     

    Thanks for your reply.

    I tried this  http://localhost/MySite/api/users/privileges/1  and try http://localhost/MySite/api/users/roles/1 , I got these errors in both cases:

    No HTTP resource was found that matches the request .

    No action was found on the controller Users that matches the request.

     

    Thanks

    Monday, February 25, 2013 4:43 PM
  • User2040953529 posted

    Hmmm - sorry, notepad coding! does it work if you do http://localhost/MySite/api/getprivileges/1 does it work? Now thinking that ActionName attribute is be MVC only, not WebApi. If you want to use the privileges without get, add an [HttpGet] attribute, get rid of the [ActionName] and name the method just Privileges.

     

    Monday, February 25, 2013 6:09 PM
  • User1850575723 posted

    James,

    I tried  http://localhost/MySite/api/getprivileges/1 as you mentioed, didnt work, I got the same error.

    I tweek my controller a little bit and this is what I found.

     My Users controller:

    public User Get(int id)  {  

    return repository.GetUserByUserID(id);     

    }     

    [HttpGet]

    public User ListByEmail(string email) {        

    return repository.GetUserByEmail(email);      

    }  

    [HttpGet]

     [ActionName("privileges")]      

    public IEnumerable<Privilege> ListPrivileges(int id) {  

    return repository.GetPrivilegesByUserID(id);

    }

    [HttpGet]

    [ActionName("roles")]

    public IEnumerable<Rol> ListRoles(int id) {  

    return repository.GetRolesByUserID(id);

    }

    Having that cotroller in place these links works just fine:

    1. returns user by UserID: http://localhost/MySite/api/user/get/1

    2. returns user by email: http://localhost/MySite/api/user?email=myemail@email.com

    3. returns user privileges by userID: http://localhost/MySite/api/user/privileges/1

    4. returns user roles by userID: http://localhost/MySite/api/user/roles/1

    I didnt change anything on my WebApiConfig, it looks the same as it is on my previous post.


    From avobe links, seems that  [ActionName] does works on web api.

     

    Questions

    1. I dont like the fisrt link :  http://localhost/MySite/api/user/get/1. How my cotroller neds to look like in order to get the user by ID like this?  http://localhost/MySite/api/user/1 , this is  I dont want to call an action to get the user by ID.

    2. In order to make links 3 and 4 to work, I had to reame parameter userID by id, i dot like the idea to force a parameter name to make it work, what should I do i order to call 3 and 4 like this:

    http://localhost/MySite/api/user/privileges?userID=1

    http://localhost/MySite/api/user/roles?userID=1

    I noticed that having the parameter name as userID then I need to call like this:

    http://localhost/MySite/api/user/roles/1?userID=1

    that  works but looks terrible, dont like it.

     

     

    Thanks for your help.

     


     


     

     

     

     

    Wednesday, February 27, 2013 12:03 AM