43

Using the new Api Controller in MVC4, and I've found a problem. If I have the following methods:

public IEnumberable<string> GetAll()

public IEnumberable<string> GetSpecific(int i)

This will work. However, if I want to retrieve some different data of a different type, it defaults to the GetAll method, even though the $.getJSON is set to the GetAllIntegers method:

public IEnumberable<int> GetAllIntergers()

(bad naming conventions)

Is it possible for me to be able to do this?

Can I only have a single GetAll method in the Web API controller?

I think it's easier to visualise what I'm trying to achieve. Here is a snippet of code to show what I'd like to be able to do, in a single ApiController:

public IEnumerable<string> GetClients()
{ // Get data
}

public IEnumerable<string> GetClient(int id)
{ // Get data
}

public IEnumerable<string> GetStaffMember(int id)
{ // Get data
}

public IEnumerable<string> GetStaffMembers()
{ // Get data
}
tpeczek
  • 23,867
  • 3
  • 74
  • 77
Neil Knight
  • 47,437
  • 25
  • 129
  • 188

2 Answers2

63

This is all in the routing. The default Web API route looks like this:

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

With the default routing template, Web API uses the HTTP method to select the action. In result it will map a GET request with no parameters to first GetAll it can find. To work around this you need to define a route where the action name is included:

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

After that you can star making requests with following URL's:

  • api/yourapicontroller/GetClients
  • api/yourapicontroller/GetStaffMembers

This way you can have multiple GetAll in Controller.

One more important thing here is that with this style of routing, you must use attributes to specify the allowed HTTP methods (like [HttpGet]).

There is also an option of mixing the default Web API verb based routing with traditional approach, it is very well described here:

Yasser Shaikh
  • 46,934
  • 46
  • 204
  • 281
tpeczek
  • 23,867
  • 3
  • 74
  • 77
  • Quick question, can I route like this and still call my methods only "Post" and have them automatically only accept HttpPost if I include an ActionNameAttribute? – Alxandr May 05 '12 at 23:14
  • @Alxandr You will still have to use AcceptVerbsAttribute (or HttpPostAttribute, HttpGetAttribute etc.) – tpeczek May 06 '12 at 17:40
  • 3
    I'm having some problems with the routing - I can define multiple "GET" methods, but if I hit /api/{controller} the server gives an HTTP 500 "multiple actions found" rather than a 404. Any idea how to block this? What I'd like is to have /api/{controller}/{id} route to "Get, Post, Put, Delete,etc ", then have /api/{controller}/{id}/{action} route to a specific action, such as /api/Customers/5/Products. Doesn't work - everything gives a "multiple actions found" error. – ShadowChaser May 16 '12 at 16:04
  • @tpeczek I am having the same problem. Should the routing with the extra {action} replace the default routing or should it be added after it? – uriDium Sep 16 '13 at 09:44
  • 2
    @uriDium It looks like you are looking for mixing traditional & verb based routing, you can read more about it here: http://blog.appliedis.com/2013/03/25/web-api-mixing-traditional-verb-based-routing/ – tpeczek Sep 16 '13 at 10:58
  • Mine isn't working. I have two separate functions, however it only returns one of them. – Si8 Jan 20 '17 at 15:27
  • 1
    @Si8 Please provider more details or reach me via email - I'll try to help. – tpeczek Jan 20 '17 at 15:29
  • @tpeczek Thank you. I had to add [HttpGet] for each function and it worked fine. Thank you. – Si8 Jan 20 '17 at 15:46
11

In case someone else faces this problem. Here's how I solved this. Use the [Route] attribute on your controller to route to a specific url.

[Route("api/getClient")]
public ClientViewModel GetClient(int id)

[Route("api/getAllClients")]
public IEnumerable<ClientViewModel> GetClients()
Archna
  • 203
  • 3
  • 8
  • 1
    route attribute link for those even more curious as to what this format is: https://learn.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2 – Callat Jun 19 '17 at 20:16
  • if your method does not start with "Get", be sure to decorate it with [HttpGet] – MC9000 Jul 23 '22 at 22:29