Luis Teijon Luis Teijon - 2 months ago 24
C# Question

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

I'm using asp.net mvc, Entityframework 6 and Unity for DI scenarios.

I couldn't find out why my DbContext object are being disposed too early.

I injected the GenericWoU class into

PeopleController
class. When I call the ListPerson action everything works ok however the DbContext is disposed. So if I try to edit any person of the list, the following error appears:


The operation cannot be completed because the DbContext has been
disposed


how can I prevent the DbContext to be disposed so early?

Here is my Generic Unit of Work 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);
}
}


Here is my
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);
}
}


Here is my 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;
}
}

Answer

The general problem is that your components take ownership over its dependencies by disposing it. A component never knows what the lifetime of its dependencies are and whether they might be used by other components later on (possibly even in the same request). So this makes it dangerous (or even plain wrong) to dispose dependencies.

Instead, as a general rule of thumb it is the one who creates a component, is responsible of its disposal. Since in your case Unity creates that object, it should dispose it (and it will).

This means that you should remove all the dispose functionality from GenericUoW. Not only is this the only correct way, it is actually much less code to maintain, since this not only affects GenericUoW, but also all the possible direct and indirect consumers of GenericUoW. In your design they all had to implement IDisposable. When applying DI correctly, you can leave this out and this can have a huge impact on the maintainability of your code.

Long story short, change the GenericUoW to the following:

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();
    }
}
Comments