DbContext已被释放。

9

我使用ASP.NET MVC 4和SQL Server 2008开发了一个Web应用程序,我创建了ContextManager类,以便在所有页面中仅有一个数据库上下文。

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;
        }
    }
}

大部分页面都可以正常运行,但在注册页面中出现了问题,我的上下文随后被销毁,显示以下错误:

无法完成操作,因为DbContext已被释放。

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

_db.Contacts.Add(contact);这一行代码处,我遇到了异常。

但是,通过更改代码,不使用ContextManager:

HotelContext _db = ContextManager.Current;

into:

HotelContext _db = new HotelContext();

问题已经解决。但我需要使用自己的上下文管理器。问题出在哪里?
5个回答

14

您的上下文在其他地方已被释放(不是您展示的代码中),因此当您从Register操作访问它时,会抛出异常。

实际上,您不应使用静态单例来访问您的上下文。为每个请求实例化一个新的DbContext实例。 请参见c#如何在多线程服务器上使用Entity Framework


问题出现在创建用户之后,我也检查了我的数据库以确保WebSecurity.CreateUserAndAccount成功进行,但是在_db.Contacts.Add(contact)处我遇到了异常。 - Ali Esfahani
1
@ken2k,ContextManager将DbContext存储在HttpContext.Current.Items中,因此每个请求都会有一个新的实例。 - mendel

7

在我的情况下,我的GetAll方法没有在lambda表达式的where子句后调用ToList()方法。使用ToList()之后,问题得到了解决。

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

4

在您的注册视图中,您可能正在“延迟加载”User的导航属性。请确保在将其发送到视图之前,在您的DbSet上使用Include方法包含它:

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

此外,使用静态属性共享 DbContext 可能会产生意想不到的副作用。

2

我曾经也遇到过同样的问题。按照上面所说的方法,我解决了它。实例化一个新的上下文实例。

尝试使用以下代码:

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

这样,每次使用您的代码时都会创建一个新的实例,您的上下文将不会被处理。


2
为什么要重写Dispose(bool)方法?
public partial class HotelContext : DbContext
{
    public bool IsDisposed { get; set; }
    protected override void Dispose(bool disposing)
    {
        IsDisposed = true;
        base.Dispose(disposing);
    }
}

接下来,检查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;
        }
    }
}

也许可以作为一个选项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接