30

I am using EF 4 to retrieve a list of Employees.

public ContentResult AutoCompleteResult(string searchText)
{
    List<Employee> list = Employee.GetAllCurrentEmployees();
    List<Employee> filteredEmployees = list
        .Where(x => x.GetName().ToLower().Contains(searchText.ToLower()))
        .ToList();

    JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
    var jsonString = jsonSerializer.Serialize(filteredEmployees).ToString();
    return Content(jsonString);
}

The list is retrieved OK, but when I serialize it, I get this exception;

System.ObjectDisposedException: The ObjectContext instance has been
 disposed and can no longer be used for
 operations that require a connection.
     Generated: Wed, 17 Nov 2010 16:06:56 GMT

 System.ObjectDisposedException: The ObjectContext instance has been
 disposed and can no longer be used for operations that require a connection. 
 at
 System.Data.Objects.ObjectContext.EnsureConnection()
 at
 System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)     at
 System.Data.Objects.ObjectQuery`1.Execute(MergeOption mergeOption)     at
 System.Data.Objects.DataClasses.EntityCollection`1.Load(List`1 collection, MergeOption mergeOption)  at
 System.Data.Objects.DataClasses.EntityCollection`1.Load(MergeOption mergeOption)     at
 System.Data.Objects.DataClasses.RelatedEnd.Load() at
 System.Data.Objects.DataClasses.RelatedEnd.DeferredLoad() at
 System.Data.Objects.DataClasses.EntityCollection`1.System.Collections.IEnumerable.GetEnumerator() at
 System.Web.Script.Serialization.JavaScriptSerializer.SerializeEnumerable(IEnumerable enumerable, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat
 serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.SerializeCustomObject(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat
 serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat
 serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object
 o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat
 serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.SerializeEnumerable(IEnumerable enumerable, StringBuilder sb, Int32 depth, Hashtable objectsInUse,
 SerializationFormat
 serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat
 serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object
 o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat
 serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object
 obj, StringBuilder output, SerializationFormat serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object
 obj, SerializationFormat serializationFormat)     at
 System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj)     at
 SHP.Controllers.EmployeeController.AutoCompleteResult(String searchText) in C:\Documents and Settings\geoffreypayne\My Documents\Visual Studio
 2010\Projects\MVC\SHP\SHP\Controllers\EmployeeController.cs:line
 623     at lambda_method(Closure , ControllerBase , Object[] )     at
 System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)    at
 System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext
 controllerContext, IDictionary`2 parameters)     at
 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext
 controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)     at
 System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassd.InvokeActionMethodWithFilters>b__a()
 at
 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter
 filter, ActionExecutingContext preContext, Func`1 continuation)    
 at
 System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassd.<>c__DisplayClassf.<InvokeActionMethodWithFilters>b__c() at
 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters)     at
 System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext
 controllerContext, String actionName)

I find this very odd. I have already retrieved the list of employees and the DataContext has been disposed. So why would I get this error?

Spikolynn
  • 4,067
  • 2
  • 37
  • 44
arame3333
  • 9,887
  • 26
  • 122
  • 205

10 Answers10

25

It sounds like you have some lazily loaded relationship properties that have not yet loaded (which has an associated "n+1" performance concern). You can try eager loading to see if this helps; otherwise, explicitly load the data for each item in the list, before you close the object-context.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • I wanted to keep lazy loading and filter out the objects that I do not need. I think judging from your answer that the serialisation does not work because of objects left as null because of lazy loading. I could create a class with only the properties I want and create a list from that. I am wondering if there is a better way, that I do not need to create such a class? – arame3333 Nov 17 '10 at 17:45
  • 2
    @arame3333 - since you are talking about `JavaScriptSerializer`, an anonymous type would do nicely - just `select new { row.Foo, row.Bar }` etc – Marc Gravell Nov 17 '10 at 18:30
  • 1
    Can you please elaborate on "otherwise, explicitly load the data for each item in the list"? Thanks. – PeterX Dec 11 '12 at 08:57
21

You could turn off lazy loading to resolve this problem.
Inside your 'using' block, try this:

yourObjectContext.ContextOptions.LazyLoadingEnabled = false;

After doing this, I was able to serialize my EF (DbContext-generated) POCO to JSON without any issue.

*Note: Since I've turned off lazy loading... I explicitly pull in related objects I need ahead of time (mostly with .Include() in my query) before the object is serialized to JSON.

Jason Parker
  • 4,960
  • 4
  • 41
  • 52
14

Thought I would chime in here with my 2 cents. We had a very big data access layer, and one of the programmers was used to using a using statement for the context like so:

using (EntityModel myContext = EntityConnection)
{
    //code in here to grab data
}

We are using the EntityConnection as a static property that serves up a dbContext per current HttpContext. Any method called after his using block would throw the exception 'ObjectContext instance has been disposed' since obviously the context was disposed of after his method call. So if you are only using one entity context per HttpContext, make sure you don't allow the garbage collector to dispose of it by using a using block.

I figured I would throw this in the answers since I know a lot of people use the entity context differently and I see a lot of using blocks in code samples out there.

Mario
  • 3,405
  • 6
  • 38
  • 48
  • 3
    Mario +1 this is the issue i was running into. im using EF to get autosuggestions based on the letter typed in a search box. I tried to use a using{} block but was getting this error. now i just use a single instance but am unsure of the correct way of disposal. could you offer any advice? – Shannow Jul 06 '11 at 14:23
2

I prefer to just load up a fat instance declared outside of the using

   Customer _custObj;
        using (RazorOne rz1 = new RazorOne())
        {
             _custObj = rz1.Customers.FirstOrDefault();      //  .Include = Lazy loading
            // Versus Implicit Load
            _custObj.AddressReference.Load();
             _custObj.Address1Reference.Load();
        }

Then I can pass her onto the View or whatever helper really wanted her..

1

It sounds like some lazy-loading or delayed evaluation that's happening; you can't assume objects are "loaded" until you actually attempt to read from them.

You need to maintain your DataContext until you are completely done handling the objects retrieved from the database to avoid these errors.

Paul Turner
  • 38,949
  • 15
  • 102
  • 166
1

I had the same problem and could resolve it by selecting a projection of the object with only the properties required by the caller, instead of returning the complete object. It seems that when you have many relations in your object, the serializer tries to navigate those.

So, (supposing that your object context is called "Entities") i would try something like this:

using ( Entities context = new Entities() )
{
       var employeeProjection = (from e in context.Employee
                         select new { e.Id, c.FirstName, e.LastName }).ToList();

        return employeeProjection;
 }
Maxolidean
  • 477
  • 6
  • 18
0

I worth taking a look at your Employee object and make sure you don't have any virtual keywords sticking out there. The virtual keyword is interpreted by Entity Framework as 'lazy-load'. We'd need to see your Employee class to make an absolute assertion why you could be seeing the exception.

Mr. Young
  • 2,364
  • 3
  • 25
  • 41
0

I had a variation on this problem. The data context was not closed, but the Object context instance has been disposed error was getting thrown anyway.

It turned out that the object had a self referential foreign key (ie the foreign key referred back into the same table). Accessing the navigation property in when it refers to a null, you get the objectcontext disposed exception instead of, say, a null pointer exception.

eg:

var a = myObject.Name; // works because myObject still has open object context
var b = myObject.SelfReference; // throws objectcontext disposed if SelfReference is null
user281806
  • 1,020
  • 9
  • 14
0

I found the best way to handle this and keep the using statement you just need to use the include, see sample below:

using (var ctx = new Context(this.connectionString)) {
  var query = ctx.[maintable]
    .Include(x => x.[theothertable])
    .FirstOrDefaultAsync(u => u.UserName.Equals(userName));
}
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
0
using (EmployeeContext db= new EmployeeContext())
    {
        var lst = db.Employees.Select(p=> new {
            EmployeeID = p.EmployeeID,
            Name = p.Name,
            Salary = p.Salary,
            Position = p.Position,
            Age = p.Age,
            Office = p.Office
        }).ToList();
        return Json(lst, JsonRequestBehavior.AllowGet);
    }
DanB
  • 2,022
  • 1
  • 12
  • 24