3

I have a data layer that uses Entity Framework 5 to connects to Sql Server. I also have a LINQ query that gets some data. This query fails when used with Web API. I get the ObjectDisposedException. Here's the query:

using (MyContext container = new myContext())
{
    return container.Sales
                    .Include("Products")
                    .Where(s => s.Id == id)
                    .FirstOrDefault();
}

The data layer is a dll, exposed by a business layer, also a dll, which is called by a web api controller. I had assumed that the JSON serializer was lazy loading the includes but none of my fixes have worked. Any ideas? I will update the question as need be if info is missing.

Here is the business layer call to the data layer:

public Sale GetSale(int id)
{
    SaleRepository s = new SaleRepository();
    return s.GetSale(id);
}

And finally the web api call to the business layer:

public Sale GetSale(int id)
{
    SaleManager s = new SaleManager();
    return s.GetSale(id);
}

Here is the exception:

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

5
  • Please show your exception and where is your code? Commented Mar 22, 2013 at 15:13
  • 1
    Have you tried setting Configuration.LazyLoadingEnabled to false on the DbContext instance to see if that resolves the problem? Commented Mar 22, 2013 at 16:31
  • Looks like only ObjectContext supports LazyLoadingEnabled. I'm using DbContext. Commented Mar 22, 2013 at 17:50
  • @CYAD DbContext has it too. In your case you should be able to call container.Configuration.LazyLoadingEnabled = false right before your query. Commented Mar 22, 2013 at 18:18
  • @PeterHansen looks like that worked, thanks! Could you put that in an answer so I can mark this as answered? Commented Mar 22, 2013 at 18:22

3 Answers 3

2

This happens because lazy loading is being performed after your DbContext has been disposed.

To resolve the issue you can disable lazy loading by doing this:

container.Configuration.LazyLoadingEnabled = false;
Sign up to request clarification or add additional context in comments.

Comments

1

There must be an issue with lazy loading and the include not working as expected - try changing your code to select the actual object and the included entities.

using (MyContext container = new myContext())
{
    var result = container
        .Sales
        .Include("Products")
        .Where(s => s.Id == id)
        .FirstOrDefault();
    result.Products.ToList();
    return result;
}

1 Comment

Tried this. Same result. It could be that I'm not using best practice. Most samples I see query the data from the controller. I want to avoid this tight coupling.
1

This is an issue with lazy loading. The more appropriate way to do this is to not dispose the DbContext till the request is done processing. You can do it in a couple of ways,

1) dispose it in the controller. framework ties the controller's life time with the requests life time.

public class MyController : ApiController
{
    private SaleManager _saleManager = new SaleManager();

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        if (disposing)
        {
            _saleManager.Dispose();
        }
    }
}

2) explicitly tie the resource with the request, (useful in cases where you are not inside a controller) using Request.RegisterForDispose()

SaleManager saleManager = new SaleManager();
Request.RegisterForDispose(saleManager);

2 Comments

The issue is that this ties the data tier to the service tier. I want them to be completely decoupled. Suppose we decide we don't like Entity Framework? We would have to modify all the layers to remove it.
The problem is that you are using entities returned from DbContext after the DbContext is disposed. Your SaleManager and SaleRepository should implement IDisposable and you would dispose the SaleManager in your controller. I am updating my answer to use SaleManager in the controller instead of DbContext.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.