Wednesday, December 3, 2014

Web API 2 - Using [FromUri] with GET Methods

Web API 2 has the default route specified as:

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

However, consider the following two GET method signatures.

   public async Task<IHttpActionResult> GetAsync(int id);
   public async Task<IHttpActionResult> GetAsync(int page, int pageSize);

Web API first does route template matching, and then it selects the method.   Based on that, these GET methods would map like this...

api/controller                              (matches route, can't find a method as all require parameters)
api/controller/1                           (matches route, get's resource with Id = 1)
api/controller/1/10                      (matches route, get's paged data)

What I really wanted was to be able to specify a route with query string parameters...  In Web-API query string parameters get bound to parameters of the same name in the controller actions, so I could also call my GetAsync(int page, int pageSize); method as follows.

api/controller?page=1&pageSize=10

That's great but without default values, the route to the resource at api/controller is still going to return this message. "The requested resource does not support http method 'GET'."
The first thought that occurred to me was to make the page and pageSize parameters optional.

public async Task<IHttpActionResult> GetAsync(int page=1, int pageSize=10);

However, this makes the methods indistinguishable from one another.  That lead me to look for another way to pass multiple parameters to my Get method. This is where the [FromUri] attribute comes into play.  Essentially it works much like the [FromBody] attribute used with Put & Post methods. Using [FromUri] specifies that we are going to use data passed in the Url to build up our object.  


The result is the following code.  Inspired by this code... 

1 comment: