如何确保 Autofac 在 EF6 DbContext 上调用 Dispose()

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

更新

找到这个小 gem 帮助我使用 DbContext Josh Kodroff - Making Entity Framework More Unit-Testable

原创

经过大量研究后,我最终决定在我的 MVC5 EF6 项目中使用 Autofac 实现 IOC。 Autofac 的文档很有帮助,但我仍然不确定是否需要在我的控制器或服务中调用 Dispose() Class?

我没有使用抽象的 UOW 和通用存储库,而是依赖于 EF6 中提供的 DbContext 和 DbSet<>。这是我的 类.

的片段

我的 DbContext

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

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

我的服务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();
    }
    .....
}

我的服务界面

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

我的控制器

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

我的 Autofac 容器

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

我已经从控制器中删除了 Dispose(),因为我知道 Autofac 会处理从 IDisposable 继承的上下文的处理。由于 ProductContext 继承自包含 Dispose() 方法的 DbContext,因此这应该可行。

我需要添加类似

的内容吗
builder.RegisterType<ProductContext>().As<DbContext>().InstancePerRequest();

或者我当前的容器会按预期调用 Dispose 工作吗?

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

感谢您的帮助,我很难在没有通用存储库的情况下使用 Autofac 找到文档,并且在 DbContext 之上使用 UOW 类似于我当前的模式。

根据文档,

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.

所以我认为如果您的 class 实现 IDisposable 那么 Dispose() 将自动为此类对象调用。如此简单,

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

将通过对象生命范围管理进行处置。

Autofac 还支持在构造函数注入中使用 Func<>。例如,您可以像往常一样注册您的数据上下文:

builder.RegisterType<ProductContext>().As<IProductContext>();

并在您的 ProductService:

中按如下方式使用它
public class ProductService : IProductService
{
    private IProductContext _dbCreator;
    public ProductService(Func<IProductContext> dbCreator)
    {
        _db = db;
    }

    public List<Product> GetProductsByCategory(string cleanCategory)
    {
        using (var dbCtx = _dbCreator())
        {

            return dbCtx.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();
        }
    }
    .....
}

基本上,您的 ProductService 现在可以访问 Func<>(_dbCreator),它会根据您的 autofac 注册创建一个新的 ProductContext 实例调用,允许您在您认为合适的时候处置实例。

写完这篇文章后我意识到你没有 IProductContext,我通常会推荐使用这种模式,但是,就你的问题而言,它并不是太重要。您可以继续使用当前的 ProductContext 注册方法,然后只需传入 Func<ProductContext> 而不是 IProductContext,即

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

private ProductContext _dbCreator;
public ProductService(Func<ProductContext> dbCreator)

抱歉,如果代码无法编译,我没有使用 IDE...希望它足够接近你明白我的意思!