WebAPI - No action was found on the controller

10,597

Solution 1

This work around did thing for me:

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


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

Basically I have added 1 more path level to my url. It finally became:

/api/v1/actor/4/details/movies

Solution 2

Try switching the order of your routes:

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

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

Order matters when creating routes. The way you have it, it's matching the first one (the default route) first, and not finding an action with the name of "1".

You might also want to look into MVC Attribute routing, I think it's a tad easier to work with: http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx

Share:
10,597
Arry
Author by

Arry

An eternal student of Computer Science. Senior Data Engineer @ Intuit

Updated on June 28, 2022

Comments

  • Arry
    Arry almost 2 years

    I am trying to make hierarchical link in my RESTapi. For example:

    Following url will give me details of actor id 1:

    /api/v1/actor/id/1/
    

    Following url is expected to give me all movies of actor id 1:

    /api/v1/actor/1/movies
    

    My routes:

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

    My Actions in ActorController:

            [HttpGet]
            public HttpResponseMessage Id(int id)
            {
                // logic
    
                return Request.CreateResponse(HttpStatusCode.OK, actor);
            }
    
            [HttpGet]
            public HttpResponseMessage Movies(int levelOneId)
            {
                // logic
                return Request.CreateResponse(HttpStatusCode.OK, movies);
            }
    

    But this setup is not working for me.

    /api/v1/actor/id/1/ gives me proper response

    But /api/v1/actor/1/movies is throwing following error:

    No action was found on the controller 'Actor' that matches the name '1'."
    

    I did follow this thread, but it did not work for me.

    Can some please suggest what wrong I am doing here? I am using MVC 4, WebAPI.

  • Arry
    Arry over 8 years
    Thanks for your answer @BFree . I already tried it, and it does not work. If I switch the order, the other route stops working. I mean this one /api/v1/actor/id/1/
  • BFree
    BFree over 8 years
    Ah, I misread your question. If you want to follow REST, you should have your route be: /api/v1/actor/1 and then change your Id action to just be called Get. That should work with the route configuration I laid out.
  • Mihai Caracostea
    Mihai Caracostea over 8 years
    This is because both urls match both routes. See my comment on the question. I'll post it as an answer if it suits your needs.
  • Arry
    Arry over 8 years
    @BFree: I did change Id to Get(int id), but it didn't work. Changing to just Get() will also not work as I need id, like this /api/v1/actor/1 Can you please explain your solution a bit?
  • Arry
    Arry over 8 years
    Thanks @Mihai for your answer. With your solution this worked: api/v1/actor/1/movies But /api/v1/actor/id/1/ is still giving error: No action was found on the controller
  • Mihai Caracostea
    Mihai Caracostea over 8 years
    /api/v1/actor/1 should also work and get routed to the Id action.
  • Mihai Caracostea
    Mihai Caracostea over 8 years
    Just make sure you've removed the other routes.
  • Arry
    Arry over 8 years
    Removed, but still same error for /api/v1/actor/id/1/ No action was found on the controller 'Actor' that matches the name '1'. Final route: config.Routes.MapHttpRoute( name: "DefaultOneLevelNested", routeTemplate: "api/v1/{controller}/{id}/{action}", defaults: new { id = "id" } );
  • Mihai Caracostea
    Mihai Caracostea over 8 years
    Use /api/v1/actor/1 or /api/v1/actor/1/id You said the first version was acceptable.
  • Arry
    Arry over 8 years
    /api/v1/actor/1 this will not work as I have other actions as well. It gives "Multiple actions were found that match the request". I am forced to stick with /api/v1/actor/1/id
  • Arry
    Arry over 8 years
    And that is why I need this structure, so that I can avoid collision between same parameter type actions: /api/v1/actor/id/1/ I can also specify /api/v1/actor/born/1966/
  • Mihai Caracostea
    Mihai Caracostea over 8 years
    Those two urls will work with this template "api/v1/{controller}/{action}/{id}"
  • Arry
    Arry over 8 years
    :That's exactly what I have in my problem :) And it does not work. May be you can post both the routes again, so that I can try as per your say from scratch. I will share the results then.
  • Carles Company
    Carles Company over 8 years
    Use attribute routing and you'll have less problems. Remember to use parameter constraints.