4
votes

As per OData Uri conventions http://www.odata.org/documentation/uri-conventions#FilterSystemQueryOption the following Uri is valid. http://services.odata.org/OData/OData.svc/Category(1)/Products?$top=2&$orderby=name

However the ASP.NET Web-API does not seem to support this (at least out of the box). It gives an error to the effect that it cannot find a controller called Category(1).

How to make this work with Web-API or is there a work around?

1
This is especially strange since the docs seem to imply that this is supported: docs.microsoft.com/en-us/aspnet/web-api/overview/…. Perhaps support for this syntax has been added since this question was asked? - Nathan Friend

1 Answers

5
votes

I'm not sure why your question didn't garner attention when you asked it..but it's a real issue. The WebAPI supports a good deal of the OData spec, but not all of it to my understanding. Although, I have yet to find a resource describing precisely what aspects work. Out of the box the default routes support one layer of nesting, not the two like in your example. So something like :

mystuff.com/Category/5?$top2&orderby=name

With that said, i think you could craft something like what you want. I haven't compiled/tested all of this, so bear with me.... In global.asax setup a pair of routes like so:

routes.MapHttpRoute(name          : "WithCategoryFilter", 
                    routeTemplate : "api/v1/{controller}({catID})/{action}/{id}",
                    defaults      : new { id = RouteParameter.Optional}        );

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

Notice the order I registered the routes--put the category filter first. The corresponding controller for these routes would look something like : :

 public class ProductCategoryController : BaseAPIController {
     public IEnumerable<Product> Products(int catID, int id) {
         var result = new List<Product>();

         //do category filtering here...

          return result;
     }
 }

So the first route would allow application of a category filter (catID) and an optional ProductID (id). When the categoryID & parenthesis are excluded the 2nd route would catch. You need two routes because there isn't a great way to filter out the parenthesis automatically.

As a side note you may be interested in another answer I wrote that identifies some other route-gymnastics your probably going to encounter.