How does ASP.NET Web.api handle two methods with names starting with GET?

I am watching the next tutorial from Microsoft. According to this guide,

In the first example, the “products” correspond to a controller named ProductsController. A request is a GET request, so the structure looks for a method on the ProductsController whose name begins with "Get ...". In addition, the URI does not contain an optional {id} segment, so the structure is looking for a method with no parameters. The ProductController :: GetAllProducts method meets all these requirements. requirements.

What happens if there are two methods, such as GetAllProducts () and GetSoldProducts ()? Both parameters have no parameters.

Your first web API tutorial

+7
source share
3 answers

Assuming you are using default routes, the short answer is: the method defined first (at the top) of your class is called. another method is not available.

NOTE. Beta behaved as described above for "matching multiple methods" - the RC and Release versions are slightly larger than OCD. It throws an error if there are several potential matches. This change eliminates the confusion of several controversial matches. At the same time, this reduces our ability to mix REST and RPC-style interfaces in one controller, based on order and overlapping routes.

Theft is liberal from another post I wrote on the subject :

WebAPI Matching Semantic

The appropriate semantics used by WebAPI are pretty simple.

  • It matches the name of the action with the verb (verb = get? Look for a method starting with "get")
  • if the parameter is passed, api looks for the action with the parameter

So, in the sample code, a GET request without a parameter corresponds to a Get*( ) function without parameters. A Get contains and ID looks for Get***(int id) .

<strong> Examples

Although the semantics of correspondence are simple, it does create some confusion for MVC developers (well, at least this developer). Let's look at a few examples:

Odd names - your get method can be called anything if it starts with "get". Therefore, in the case of the widget controller, you can name your functions GetStrawberry() , and it will still match. Think of a match as something like: methodname.StartsWith("Get")

Several matching methods. What happens if you have two Get methods without parameters? GetStrawberry() and GetOrange() . As far as I can tell, the function defined first (the top of the file) in your code wins ... weird. This has a side effect when some methods in your controller are not available (at least with default routes) ... a stranger.

UPDATE

@WinFXGuy - It was a little time to add a comment, but ...

Do not come to conclusions! I tried to answer your question, but this is only half the story. There are many possibilities for changing the default behavior.

First , WebAPI supports most of the oData spec. If you are IQueryable bubbles IQueryable to your controller, oData parameters are automatically integrated with the query object. It accepts parameters like $filter , $top and $skip . Therefore, in your case, you can write one method and pass something like $filter=sale_date neq null .

In addition, you can apply the [ResultLimit] attribute so that people do not request 15 billion records.

Second you can change the routes. The default routes are directed to a RESTful api, where you usually have 1 controller per object. You can change routes and create an RPC style.

If you look at my linked post, I’ll explain how I saved the default route binding, added “auxiliary folders”, and also allowed additional method calls for scripts where I need GetAllProducts() and GetSoldProducts() .

+8
source

There are two possible solutions to this particular problem:

  • Modify the MapHttpRoute call to specify an action name. (I use the syntax for self-hosting):

      config.Routes.MapHttpRoute( "API Route 1", "api/{controller}/{action}"); config.Routes.MapHttpRoute( "API Route 2", "api/{action}", new { controller = "products" }); 

    This way your http client will call:

    api/products/GetAllProducts OR api/GetAllProducts api/products/GetSoldProducts OR api/GetSoldProducts

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

  • Place each method in a separate controller (ProductsController, SoldProductsController). So you can call api/products and api/soldproducts to get your results.


A related topic ... in a situation where you have multiple Get actions that have one primitive argument of the same type, the ASP.NET Web API will look at the argument name to allow the overloaded action to be called.

For example, if you have two actions:

 GetProductByName(string name) GetProductByCategory(string category) 

your http client can call

 api/products?name=hammer api/products?category=toys 

and the routing mechanism will cause the correct action.

+11
source

Adding an answer to reflect that the latest version of the web API supports the [Route] attribute natively

 [Route("api/products")] public IEnumerable<Product> GetAllProducts(){} [Route("api/products/sold")] public IEnumerable<Product> GetSoldProducts(){} 
+4
source