简体   繁体   中英

DbContext has been disposed

I developed a web application with ASP.NET MVC 4 and SQL Server 2008, I create ContextManager class to have only one database context in all pages.

public static class ContextManager
{
    public static HotelContext Current
    {
        get
        {
            var key = "Hotel_" + HttpContext.Current.GetHashCode().ToString("x")
                      + Thread.CurrentContext.ContextID.ToString();
            var context = HttpContext.Current.Items[key] as HotelContext;
            if (context == null)
            {
                context = new HotelContext();
                HttpContext.Current.Items[key] = context;
            }
            return context;
        }
    }
}

It works properly in most of the pages, but in registration page something goes wrong and my context gone deposed with following error:

The operation cannot be completed because the DbContext has been disposed.

public ActionResult Register ( RegisterModel model )
{
    if ( ModelState.IsValid )
    {
        // Attempt to register the user
        try
        {
            WebSecurity.CreateUserAndAccount( model.UserName, model.Password,
                                              new
                                               {
                                                      Email = model.Email,
                                                      IsActive = true,
                                                      Contact_Id = Contact.Unknown.Id
                                               } );

            //Add Contact for this User.
            var contact = new Contact { Firstname = model.FirstName, LastName = model.Lastname };
            _db.Contacts.Add( contact );
            var user = _db.Users.First( u => u.Username == model.UserName );
            user.Contact = contact;
            _db.SaveChanges();
            WebSecurity.Login( model.UserName, model.Password );

at the line _db.Contacts.Add( contact ); I got the exception.

But without using ContextManager by changing

HotelContext _db = ContextManager.Current;

into:

HotelContext _db = new HotelContext();

the problem was solved. But I need to use my own ContextManager. What is the problem?

Your context has been disposed somewhere else (not in the code you've shown), so basically when you access it from your Register action, it throws the exception.

Actually, you shouldn't use a static singleton to access to your context. Do instantiate a new DbContext instance for each request . See c# working with Entity Framework in a multi threaded server

In my case, my GetAll method was not calling ToList() method after where clause in lambda expression. After using ToList() my problem was solved.

Where(x => x.IsActive).ToList();

You are probably 'lazy-loading' a navigation property of User in your registration view. Make sure you include it by using the Include method on your DbSet before sending it to the view:

_db.Users.Include(u => u.PropertyToInclude);

Also, sharing DbContext s with a static property may have unexpected side effects.

I used to have the same problem. I solved it doing as it was said above. Instantiate a new instance of your context.

Try using this:

            using (HotelContextProductStoreDB = new ProductStoreEntities())
            {
                //your code
            }

This way it'll be created a new instance everytime you use your code and your context will not be disposed.

Why override the Dispose(bool)?

public partial class HotelContext : DbContext
{
    public bool IsDisposed { get; set; }
    protected override void Dispose(bool disposing)
    {
        IsDisposed = true;
        base.Dispose(disposing);
    }
}

And, then check IsDisposed

public static class ContextManager
{
    public static HotelContext Current
    {
        get
        {
            var key = "Hotel_" + HttpContext.Current.GetHashCode().ToString("x")
                      + Thread.CurrentContext.ContextID.ToString();
            var context = HttpContext.Current.Items[key] as HotelContext;
            if (context == null || context.IsDisposed)
            {
                context = new HotelContext();
                HttpContext.Current.Items[key] = context;
            }
            return context;
        }
    }
}

Maybe, can be an option.

If you need to check if your DbContext is still valid to use (not disposed), DbContext needs to be recreated: See answer on defining a IsDisposed() extended method for a DbContext partial class https://stackoverflow.com/a/74894375/1518501

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM