OData library

Asp.net Core Mvc Controls Toolkit has the capability to handle queries passed in the query string in OData format through the MvcControlsToolkit.Core.OData nuget package that depends just on the MvcControlsToolkit.Core.Business and MvcControlsToolkit.Core.Options Mvc Controls Toolkit packages.

MvcControlsToolkit.Core.OData is added automatically as a dependency when you install the MvcControlsToolkit.ControlsCore package.

OData queries exraction from the url is enabled by adding the following code in your ConfigureServices in Startup.cs:

services.AddODataQueries();
The AddODataQueries extension method is contained in the MvcControlsToolkit.Core.Extensions namespace and must be placed after your services.AddMvcControlsToolkitControls, if included.

In order to get the Odata query extracted by the url, just inject IWebQueryProvider (MvcControlsToolkit.Core.OData namespace) in any controller you would like to enrich with OData queries:

public class FoodController: 
    ServerCrudController<FoodViewModelFoodViewModelint?>
{
    public FoodController(FoodRepository repository, 
            IStringLocalizerFactory factory, IHttpContextAccessor accessor, 
            IWebQueryProvider queryProvider) :
        base(factory, accessor)
    {
            
        Repository = repository;
        this.queryProvider = queryProvider;
    }
 
    public IWebQueryProvider queryProvider { getprivate set; }

The IWebQueryProvider may be used to get a QueryDescription<T> object that is specific for an item ViewModel T by calling its Parse<T> method.

var query = queryProvider.Parse<FoodViewModel>();

QueryDescription<T> common methods and properties

Page: long
The current page, if any, otherwise 1
Skip: long
The current query skip, if any, otherwise 0.
Take: long?
The current query take if any
GetFilterExpression(): Expression<Func<T, bool>>
The current filter expression in LinQ format. You just need to insert it in a LinQ Where
GetSorting(): Func<IQueryable<M>, IOrderedQueryable<T>>
GetSorting<M>(): Func<IQueryable<M>, IOrderedQueryable<M>>
Returns a function that apply the current sorting to an IQueryable<T>. Use the second overload if the query contains grouping/aggregations and the aggregated item ViewModel M differs from T.
GetGrouping(): Func<IQueryable<T>, IQueryable<T>>
GetGrouping<M>(): Func<IQueryable<T>, IQueryable<M>>
Returns a function that apply the current grouping to an IQueryable<T>. Use the second overload if the the aggregated item ViewModel M differs from T.
void AttachEndpoint(string baseUrl, bool returnsjSon=false,
string bearerToken=null, string ajaxId=null)
Declares the url where the query should be sent(baseUrl), specifies if a Json response is expected, and a bearerToken to send in the request header. If ajaxId is not null the request must be send with ajax and the returned Html must be attached to the html node whose id is ajaxId. The ajax update has a default "blocking animation" that grays out the grid and blocks any interaction with it. You may change this animation and/or add other effects by providing an endpoint name after the Html node id in the ajaxId parameter. The two strings must be separated by a blank, like in this example: "grid1 myEndpoint".

Other usefull methods

string ToString()
Get the url passed with AttachEndpoint with attached the query encoded in the object in OData format.
AddToUrl(string url, bool disablePaging=false)
Get the url passed as argument with attached the query encoded in the object in OData format. If disablePaging is true paging information are not rendered.
CustomUrlEncode(Func<string, string> func)
OData query string clauses are url encoded. This method passes a custom url encode function. Usefull for debugging.
AddFilterCondition(Expression<Func<T, bool>> filter, bool useOr=false)
Add a LinQ filter condition to the filter already contained in the query. If useOr is true the new condition is added in logical or with all preexisting conditions, otherwise in logical and.
string GetGroupDetailUrl(Type type, object model, string baseUrl = null)
If the query encoded in the object contains grouping/aggregations it gets the detail url associated to the current grouping and to the grouping item model. The Odata query is attached to the url passed in the argument if not null, otherwise to the url declared with AttachEndpoint. type is the type of the grouping ViewModel.

Fork me on GitHub