Search code examples
c#entity-framework-6autofacdispose

How to ensure that Autofac is calling Dispose() on EF6 DbContext


UPDATE

Found this little gem which helped me with DbContext Josh Kodroff - Making Entity Framework More Unit-Testable

Original

After doing a lot of research I finally decided to implement IOC using Autofac in my MVC5 EF6 project. Autofac's documentation has been helpful, but I'm still not sure about whether or not I need to call Dispose() either in my Controller or Service Class?

I'm not using an abstracted UOW and Generic Repository, but just relying on DbContext and DbSet<> provided in EF6. Here's a snippet of my classes.

My DbContext

public class ProductContext : DbContext
{
    public ProductContext() : base("ProductContext")
    {
    }

    public DbSet<Availability> Availability { get; set; }       
    public DbSet<Category> Categories { get; set; } 
    ....
 }

My Service Class

    public class ProductService : IProductService
{
    private ProductContext _db;
    public ProductService(ProductContext db)
    {
        _db = db;
    }

    public List<Product> GetProductsByCategory(string cleanCategory)
    {
        return _db.Products
             .Include(p => p.Options.Select(o => o.OptionGroup))
                 .Include(p => p.Associations.Select(a => a.AssociatedGroup))
                 .Include(p => p.Variations).Include(p => p.Manufacturer)
                 .Where(p => p.Active && p.Category.Name.ToUpper().Equals(cleanCategory)).ToList();
    }
    .....
}

My Service Interface

    public interface IProductService
{
    List<Product> GetProductsByCategory(string cleanCategory);
    ....
}

My Contoller

    public class ProductsController : Controller
{
    private IProductService _productService;
    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    //GET: Products/
    public ActionResult Index(string category)
    {
        if (String.IsNullOrEmpty(category))
        {
            return HttpNotFound();
        }

        string cleanCategory = urlScrubber(category);
        var viewModel = new ProductsVM();
        viewModel.ProductList = _productService.GetProductsByCategory(cleanCategory);
}

My Autofac Container

var builder = new ContainerBuilder();

        // Register your MVC controllers.
        builder.RegisterControllers(typeof(MvcApplication).Assembly);

        // REGISTER COMPONENTS HERE:
        builder.RegisterType<ProductContext>().AsSelf().InstancePerRequest();
        builder.RegisterType<ProductService>().As<IProductService>().InstancePerRequest();

        // Set the dependency resolver to be Autofac.
        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

I have removed Dispose() from the controller with the understanding that Autofac would handle the disposal of contexts that inherit from IDisposable. Since ProductContext inherits from DbContext which includes a Dispose() Method, this should work.

Do I need to include something like

builder.RegisterType<ProductContext>().As<DbContext>().InstancePerRequest();

or will my current container work as expected calling Dispose?

builder.RegisterType<ProductContext>().AsSelf().InstancePerRequest();

Thanks for any help, I'm having a hard time locating documentation using Autofac without a generic repository and UOW on top of DbContext similar to my current pattern.


Solution

  • As per the doucmentation,

    Autofac integration libraries standard unit-of-work lifetime scopes will be created and disposed for you automatically. Autofac’s ASP.NET MVC integration, a lifetime scope will be created for you at the beginning of a web request and all components will generally be resolved from there. At the end of the web request, the scope will automatically be disposed - no additional scope creation is required on your part.

    So I think if your class implments IDisposable then Dispose() would be automatically called for such objects. So simply,

    builder.RegisterType<ProductContext>().As<DbContext>().InstancePerRequest();
    

    Would do the Disposal via object life scope management.