DbContext 对象已被处置:如何防止对象被处置?

DbContext object has been disposed: how can I prevent the object to be disposed?

我在 DI 场景中使用 asp.net mvc、Entityframework 6 和 Unity。

我无法找出我的 DbContext 对象被过早处置的原因。

我将 GenericWoU class 注入 PeopleController class。当我调用 ListPerson 操作时,一切正常,但 DbContext 已处理。因此,如果我尝试编辑列表中的任何人,则会出现以下错误:

The operation cannot be completed because the DbContext has been disposed

如何防止 DbContext 过早被释放?

这是我的通用工作单元 class:

    public class GenericUoW : IDisposable, IGenericUoW
    {
        private readonly DbContext entities = null;
        public Dictionary<Type, object> repositories = new Dictionary<Type, object>();

        public GenericUoW(DbContext entities)
        {
            this.entities = entities;
        }

    public IRepository<T> Repository<T>() where T : class
    {
        if (repositories.Keys.Contains(typeof(T)) == true)
        {
            return repositories[typeof(T)] as IRepository<T>;
        }

        IRepository<T> repo = new GenericRepository<T>(entities);
        repositories.Add(typeof(T), repo);
        return repo;
    }

    public void SaveChanges()
    {
        entities.SaveChanges();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                entities.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

这是我的 GenericRepository class:

class GenericRepository<T> : IRepository<T> where T : class
{
    private readonly DbContext entities = null;
    private DbSet<T> _objectSet;

    public GenericRepository(DbContext _entities)
    {
        entities = _entities;
        _objectSet = entities.Set<T>();
    }

    public IEnumerable<T> GetAll(Func<T, bool> predicate = null)
    {
        if (predicate != null)
        {
            return _objectSet.Where(predicate);
        }

        return _objectSet.AsEnumerable();
    }

    public T Get(Func<T, bool> predicate)
    {
        return _objectSet.First(predicate);
    }

    public void Add(T entity)
    {
        _objectSet.Add(entity);
    }

    public void Attach(T entity)
    {
        _objectSet.Attach(entity);
    }

    public void Delete(T entity)
    {
        _objectSet.Remove(entity);
    }
}

这是我的 ContainerBootstrapper class:

public class ContainerBootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = BuildUnityContainer();
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        return container;
    }
    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        DbContext entities = new TeijonStuffEntities();
        container.RegisterInstance(entities);

        GenericUoW GUoW = new GenericUoW(entities);
        container.RegisterInstance(GUoW);

        MvcUnityContainer.Container = container;
        return container;
    }
}

普遍的问题是您的组件通过处置它来获取其依赖项的所有权。一个组件永远不知道它的依赖项的生命周期是多少,以及它们以后是否会被其他组件使用(甚至可能在同一个请求中)。所以这使得处理依赖关系变得危险(甚至是完全错误的)。

相反,根据一般经验,它是创建组件的人,负责处理组件。因为在你的情况下 Unity 创建了那个对象,它应该处理它(它会)。

这意味着您应该从 GenericUoW 中删除所有处置功能。这不仅是唯一正确的方法,而且实际上需要维护的代码要少得多,因为这不仅会影响 GenericUoW,还会影响 GenericUoW 的所有可能的直接和间接消费者。在您的设计中,它们都必须实现 IDisposable。正确应用 DI 时,您可以忽略它,这会对代码的可维护性产生巨大影响。

长话短说,将 GenericUoW 更改为以下内容:

public sealed class GenericUoW : IGenericUoW
{
    private readonly Dictionary<Type, object> repositories =new Dictionary<Type, object>();
    private readonly DbContext entities;

    public GenericUoW(DbContext entities)
    {
        this.entities = entities;
    }

    public IRepository<T> Repository<T>() where T : class
    {
        if (!repositories.Keys.Contains(typeof(T))) {
            IRepository<T> repo = new GenericRepository<T>(entities);
            repositories.Add(typeof(T), repo);
        }

        return (IRepository<T>)repositories[typeof(T)];
    }

    public void SaveChanges() {
        entities.SaveChanges();
    }
}