user3953989 user3953989 - 1 month ago 9
reST (reStructuredText) Question

How to return IQueryable from an oData V4 api action

Following the tutorial here I'm trying to return IQueryable but I get error The operation cannot be completed because the DbContext has been disposed

public class ProductsController : ODataController
{
[EnableQuery]
public IQueryable<Product> Get()
{
return GetRepository<Product>().GetQueryable();
}
}


GetRepository() is part of a larger generic DI and Unit of work pattern class that basically

public Repository(DbContext context)
{
Context = context;
DbSet = Context.Set<T>();
}

public virtual IQueryable<T> GetQueryable()
{
IQueryable<T> query = DbSet;

return query;
}

Answer

When you return an IQueryable from a controller, you don't have control over when that IQueryable is run. What is happening is that your DbContext is being disposed before the Web API plumbing is getting around to running the IQueryable and returning the results.

What you are doing with GetRepository is referred to as the Service Locator Pattern. However Web API has a mechanism for doing Dependency Injection, which will give you more deterministic control of the lifetime of your resources.

https://www.asp.net/web-api/overview/advanced/dependency-injection

Using this approach, you constructor inject your services (the return type of GetRepository), and then override Dispose on your controller so you can clean up your constructor injected services. Web API will call Dispose on your controller once it has finished running and returning the results from your IQueryable, and thus your lifetime issues will be fixed.

There are wrappers on NuGet for many of the common IOC containers to allow them to work automatically with Web API.