We have WEB API which uses OData. Our controllers inherit from EntitySetController and now we are changing it to AsyncEntitySetController
Patch, Post, Put, Get(key) methods are easy to change, but the problem is with Get method.
In EntitySetController it returns IQueryable, filters specified in URI are further applied and then query is executed.
But in AsyncEntitySetController it returns IEnumerable so we need to call ToListAsync in method and I am affraid that parameters from URI are not applied or query is called before the filters are applied and filters are applied to memory collection.
How to achieve that it behaves the same way as with EntitySetController, so:
I managed to solve it by using QueryOptions.ApplyTo(query)
. So my previous code in controller class derived from EntitySetController
:
public override IQueryable<Entity> Get()
{
return this.DataContext.Entities;
}
was transformed into controller class derived from AsyncEntitySetController
, like this:
public override Task<IEnumerable<Entity>> Get()
{
var query = this.DataContext.Entities;
query = (IQueryable<Entity>)this.QueryOptions.ApplyTo(query);
return query.ToListAsync();
}
One note to mention. Skip from query parameters in URI gets applied twice, see: WebAPI OData $Skip on custom IQueryable double applied
You can implement your own EnableQuery attribute like this and decorate Get method with that in controller:
public sealed class EnableQueryIgnoreSkipAttribute : EnableQueryAttribute
{
public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
{
// Do not apply Skip
var skipOption = new SkipQueryOption("0", queryOptions.Context);
typeof(ODataQueryOptions).GetProperty(nameof(ODataQueryOptions.Skip)).SetValue(queryOptions, skipOption, null);
return base.ApplyQuery(queryable, queryOptions);
}
}
And decorate method like this:
[EnableQueryIgnoreSkip]
public override Task<IEnumerable<Entity>> Get()