Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC, Unity and IDisposable

I am using ASP.Net MVC 4, EF and Unity for DI. Also uses UnitOfWork pattern. Trying to figure out the best way to implement this. I have the code like below. The problem I am having is the Dispose() in Business and Repository layer never get called now, only the Destructor in both get called, so the objects seem to be never disposed. Please answer the following

  1. Do I really need the IDisposable implementation in Business and Repository layer (if Unity is already taking care of it)

  2. What should I do to get the Dispose() called(should I add it to the Controller too and Dispose all other objects or use some specific LifeTime manager)

  3. Whether I should use the Singleton Instance of each or dispose it in each request as it is in the web environment.

Global.asax.cs:

private static IUnityContainer _unityContainer;

protected void Application_Start()
{
   _unityContainer = UnityBootstrapper.SetupUnity();
   _unityContainer.RegisterType<IController, ProductController>("Product");  
   DependencyResolver.SetResolver(new Microsoft.Practices.Unity.Mvc.UnityDependencyResolver(_unityContainer));
}  

UnityBootstrapper.cs:

public class UnityBootstrapper
{
    public static IUnityContainer SetupUnity()
    {
        UnityContainer container = new UnityContainer();
        container.RegisterType<IProductDbContext, ProductDbContext>()
                 .RegisterType<IUnitOfWork, UnitofWork>(new InjectionConstructor(new ResolvedParameter(typeof(IProductDbContext))))
                 .RegisterType<IProductRepository, ProductRepository>()
                 .RegisterType<IProductBusiness, ProductBusiness>();
    }
}

ProductController.cs:

public class ProductController : ControllerBase
{
    private readonly IProductBusiness _productBusiness;        

    public ProductController(IProductBusiness productBusiness)
    {
        _productBusiness = productBusiness;
    }

    //No Dispose for this
}

ProductBusiness.cs:

public class ProductBusiness : IProductBusiness, IDisposable
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IProductRepository _productRepository;
    public ProductBusiness(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
        _productRepository = _unitOfWork.ProductRepository;
    }

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

    protected override void Dispose(bool disposing)
    {
        if (!_isDisposed)
        {
            if (disposing)
            {
                if (_productRepository != null) _productRepository.Dispose();
                if (_unitOfWork != null) _unitOfWork.Dispose();
            }

            _isDisposed = true;
         }
    }

    ~ProductBusiness()
    {
         Dispose(false);
    }
}

ProductRepository.cs:

public class ProductRepository : IProductRepository, IDisposable
{
    private readonly IProductDbContext _context;

    public ProductRepository(IProductDbContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        _context = context;
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (!_isDisposed)
        {
            if (disposing)
            {
                if (_context != null) _context.Dispose();
            }

            _isDisposed = true;
        }
    }

    ~ProductRepository()
    {
        Dispose(false);
    }
}   
like image 251
SA. Avatar asked Feb 19 '14 21:02

SA.


2 Answers

You don't really need to dispose objects, unless you do something specific during disposing process. DI containers take care of object lifetime for you.

Sometimes UoW implementation involves saving the changes on disposal. Try avoiding this. But if this is unavoidable, you can implement factory for that:

public interface IUnitOfWorkFactory
{
    IUnitOfWork Create();
}

public class UnitOfWorkFactory : IUnitOfWorkFactory
{
    public IUnitOfWork Create()
    {
        return new UnitOfWork();
    }
}

public class UnitOfWork : IUnitOfWork, IDisposable
{
    // other implementation


    public void Dispose()
    {
        context.SaveChanges();
    }
}

and then consumer will do something like this:

public MyController(IUnitOfWorkFactory workFactory)
{
    this.workFactory = workFactory;
}

public ActionResult DoSomething()
{
    using(var uow = workFactory.Create())
    {
        //do work
    }
}

This DI book chapter talks about disposable objects.

like image 66
trailmax Avatar answered Sep 24 '22 15:09

trailmax


While Unity will manage disposing of your registered types, you still have to call dispose on your IOC container so that it does it for them.

Do it from Application_End and it should be fine.

    protected void Application_End()
    {
        _unityContainer .Dispose();
    }
like image 31
shenku Avatar answered Sep 21 '22 15:09

shenku