Wednesday, 12 October 2016

oData like filtering and paging in ASP.NET Web API

oData is quite nice. It lets you present a query and filter friendly REST API endpoint by providing you a standard you can stick to. What's more - there is a great set of tooling available in you want to bind your datasource wrappers/providers like EntityFramework or otherwise if you are building your WebAPIs using ASP.NET MVC. It is specifically helpful if you want to add "free" filtering and paging abilities in your WebAPI. The Queryable data source and oData model binder takes care of it for you.

However, when you want to build real world application, often you do not want to expose your data source directly or sometimes it is not practical at all. In those scenarios if you want to support oData like filtering and paging capabilities in your WebAPI action, then it is a little more involved.

There are some options available.

1. Build a IQueryable data source and expose that. It is not practical in most of the cases though.
2. Build a custom model binder that can pick the paging and filtering expressions from QueryString and bind it to a custom model parameter before executing the WebAPI action.

Help links: Link # 1, Link # 2

Here is a simple run down.

Create a simple FilterModel class (you can build similar paging model too).

public class FilterModel
{
        public Dictionary FilterCriteria { get; set; }
}

Create a simple FilterModelBinder class that implements IModelBinder interface.

public class FilterModelBinder : IModelBinder
    {
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(FilterModel))
            {
                return false;
            }
            FilterModel model = new FilterModel();
            model.FilterCriteria = new Dictionary();
            var qs = actionContext.Request.GetQueryNameValuePairs();
            foreach (var kv in qs)
            {
                model.FilterCriteria.Add(kv.Key, kv.Value);
            }
            bindingContext.Model = model;
            return true;
}

Bind the specific WebAPI action's parameter with custom modelbinder.

public string Get(int id, [ModelBinder(typeof(FilterModelBinder))] FilterModel model)
        {
            return "value";
        }

Now, you can try a url like: http://localhost:3539/api/values/5?firstname eq 'David'&pageNumber=10

You can see the filtering and paging criteria gets populated and passed on to the WebAPI action method for your custom implementation to take over.

No comments:

Post a Comment