The operation cannot be completed because the DbContext has been disposed using MVC 4

36,351

The problem you're experiencing is due to LINQ's deferred execution. It's quite the gotcha for developers who haven't yet realized how LINQ works under the hood. I have a great blog post about it, but the core concept is that you must force an enumeration on the collection to cause the LINQ code to run immediately instead of later. This means changing this:

model.PublisherList = context.Publishers.Select(x =>
    new SelectListItem()
    {
        Text = x.Name,
        Value = x.Id.ToString()
    });

to this:

model.PublisherList = context.Publishers.Select(x =>
    new SelectListItem()
    {
        Text = x.Name,
        Value = x.Id.ToString()
    }).ToList();

Note the .ToList() there which forces the enumeration.

Your LINQ query is deferred meaning that it is not being run at your controller but instead afterwards, probably in your view where you loop over the collection (which forces the enumeration and thus runs the LINQ). Because you're using the using statement to dispose of your DB context (which is of course good practice), the context is disposed of before you reach the view, which executes the code against the disposed context. Forcing the enumeration within the using statement will run the code at that time, instead of later when the context is disposed, and prevent this issue.

Share:
36,351

Related videos on Youtube

Sandeep Shekhawat
Author by

Sandeep Shekhawat

Updated on July 09, 2022

Comments

  • Sandeep Shekhawat
    Sandeep Shekhawat almost 2 years

    I know that this Question is asked so many times. I have read and implemented all solution but didn't get success. I am getting this error when I retrieve data from database using EF and binds with model after that use this model on View.

    My controller code is

    using System.Linq;
    using System.Web.Mvc;
    using JsonRenderingMvcApplication.Models;
    
    namespace JsonRenderingMvcApplication.Controllers
    {
        public class PublisherController : Controller
        {
            public ActionResult Index()
            {
                PublisherModel model = new PublisherModel();
                using (DAL.DevelopmentEntities context = new DAL.DevelopmentEntities())
                {               
                    model.PublisherList = context.Publishers.Select(x =>
                                            new SelectListItem()
                                            {
                                                Text = x.Name,
                                                Value = x.Id.ToString()
                                            }); ;
                               }
                return View(model);
            }
    
        }
    }
    

    My View code is

    @model JsonRenderingMvcApplication.Models.PublisherModel
    
    @{
        ViewBag.Title = "Index";
    }
    <div>
        @Html.DisplayFor(model=>model.Id)
        @Html.DropDownListFor(model => model.Id, Model.PublisherList);
    </div>
    <div id="booksDiv">
    
    </div>
    

    My model code is

    using System.Collections.Generic;
    using System.Web.Mvc;
    using System.ComponentModel.DataAnnotations;
    
    namespace JsonRenderingMvcApplication.Models
    {
        public class PublisherModel
        {
            public PublisherModel()
            {
                PublisherList = new List<SelectListItem>();
            }
    
            [Display(Name="Publisher")]
            public int Id { get; set; }
            public IEnumerable<SelectListItem> PublisherList { get; set; }
        }
    }
    

    My entity code is

    namespace JsonRenderingMvcApplication.DAL
    {
        using System;
        using System.Collections.Generic;
    
        public partial class Publisher
        {
            public Publisher()
            {
                this.BOOKs = new HashSet<BOOK>();
            }
    
            public int Id { get; set; }
            public string Name { get; set; }
            public string Year { get; set; }
    
            public virtual ICollection<BOOK> BOOKs { get; set; }
        }
    }     
    

    Yes this entity has a navigation property but I don't want to that entity data so I don't want to include that.

    Thanks

    • Wagner DosAnjos
      Wagner DosAnjos over 10 years
      What line throws the exception?
    • Sandeep Shekhawat
      Sandeep Shekhawat over 10 years
      @wdosanjos This line " @Html.DropDownListFor(model => model.Id, Model.PublisherList);" throws an exception as Title of post
    • RBT
      RBT over 8 years
      Though not directly linked with this problem but I had interesting finding for same error. I had this unitOfWork class (having dbcontext object) and class ABC. Class ABC was using dbContext object through unitOfWork class. Both class ABC and unitOfWork were getting instantiated through windsor castle DI container. I was getting very same error and the issue was in the way I had registered class ABC in the initialization of DI container. I had written code like Register(Component.For<IABC>().ImplementedBy<ABC>() .LifeStyle.Transient ) I had missed the code in bold to end up with this issue.
  • Sandeep Shekhawat
    Sandeep Shekhawat over 10 years
    Thanks for response. Can you please explain more that what does '.ToList()'? +1 to you.
  • David L
    David L over 10 years
    Excellent answer. @Sandeep. If you are curious as to what .ToList() does, I highly recommend reading the documentation. msdn.microsoft.com/en-us/library/bb342261%28v=vs.110%29.aspx
  • Haney
    Haney over 10 years
    @Sandeep for sure, see David's comment on what .ToList() does. It basically creates a list of the objects in your enumerable.
  • Sandeep Shekhawat
    Sandeep Shekhawat over 10 years
    Thanks @DavidL to share this link. If I am not correct then please correct me about this. I am getting that ".ToList() is an extension method of Enumerable<> collection and returns a list of IEnumerable<> type. Thanks
  • Haney
    Haney over 10 years
    @Sandeep exactly. However List<T> does not support deferred execution and so the code is executed immediately. IEnumerable<T> supports deferred execution, which is essential to the efficiency of LINQ across multiple projections/filters/queries. This is why LINQ almost always works against the IEnumerable<T> or IQueryable<T> interface.
  • Sandeep Shekhawat
    Sandeep Shekhawat over 10 years
    Thanks @DavidHaney. I got it. +1
  • Sandeep Shekhawat
    Sandeep Shekhawat over 10 years
    @DavidHaney After implementation of it. I am getting this error "LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression."
  • Tommy
    Tommy over 10 years
    @Sandeep - this is because .ToString() has no representation in SQL. To get rid of this error, move your .ToList() to before the .Select(). db.Publishers.ToList().Select(x=>new SelectListItem...)
  • Sandeep Shekhawat
    Sandeep Shekhawat over 10 years
    @Tommy Thanks.It's superb!!+1
  • Christine
    Christine about 8 years
    I tried this, but now I'm getting this in my Error Log: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
  • Guilherme de Jesus Santos
    Guilherme de Jesus Santos almost 8 years
    So, ToList() creates a cache of results?