9

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?

Marcos Dimitrio
  • 6,651
  • 5
  • 38
  • 62
Ali Esfahani
  • 119
  • 1
  • 3
  • 7

5 Answers5

14

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

Community
  • 1
  • 1
ken2k
  • 48,145
  • 10
  • 116
  • 176
  • the problem occours after creating the user and I also checked my db to be sure, WebSecurity.CreateUserAndAccount is proceeding successfully but at _db.Contacts.Add( contact ); i got the exception. – Ali Esfahani Sep 05 '13 at 11:56
  • 1
    @ken2k, the ContextManager is storing the DbContext in HttpContext.Current.Items, so it is will be a new instance per request. – mendel Apr 30 '15 at 18:24
7

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();
4

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 DbContexts with a static property may have unexpected side effects.

Henk Mollema
  • 44,194
  • 12
  • 93
  • 104
2

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.

GreatNews
  • 575
  • 5
  • 13
2

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.

antonio
  • 548
  • 8
  • 16