使用工作单元和存储库模式的MVC的Autofac关系问题

时间:2018-12-31 00:52:00

标签: c# model-view-controller autofac

我目前正在使用依赖项注入(autofac)设置新的MVC Web应用程序。我真的很了解依赖注入,所以我想错过一些东西。我有一个可行的解决方案(在下面发布),但是我觉得我的解决方案通过解决依赖关系违背了Autofac的尝试。

基本上,我有一个服务,该服务具有多个UnitOfWork,每个UnitOfWork具有多个存储库,并且它们共享dbcontext的单个实例(由UnitOfWork拥有)。我需要为UnitOfWork构建的IDatabaseFactory可以向下传递到存储库中。这是为了防止存储库处置由singleUnitOfWork实例中的另一个存储库使用的上下文。

这是我尝试过的。

服务的简化模型

public class NewsletterService :INewsletterService
{
    TestUnitOfWork _uow1;
    TestUnitofWork2 _uow2;

    public NewsletterService(TestUnitOfWork uow, TestUnitOfWork2 uow2 )
    {
        _uow1 = uow;
        _uow2 = uow2;
    }
}

一个简单的实现的工作单元(基于msdn上的示例的界面)
我忽略了界面,它只是做与问题无关的东西(我们无法通过构建)。 ContactSubscription只是一个模型。

public class TestUnitOfWork : UowBase, IUnitOfWork
{
    public TestUnitOfWork(IDatabaseFactory factory,
        GenericRepository<ContactSubscription> repo)
        : base(factory)
    {

    }
}

通用仓库

public class GenericRepository <TEntity> : IRepository<TEntity> where TEntity : class
{
    private readonly ApplicationDbContext _context;
    private readonly DbSet<TEntity> _dbSet;

    public GenericRepository(IDatabaseFactory factory)
    {
        _context = factory.Get();
        _dbSet = _context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null, 
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        // ...
    } 
}

数据库工厂实现

public class UniqueDatabaseFactory : IDatabaseFactory
{
    private ApplicationDbContext _context;
    public Guid guid = Guid.NewGuid();  // using guid to quickly check instances.
    public ApplicationDbContext Get()
    {
        return _context ?? ( _context = ApplicationDbContext.Create());
    }
}

,注册如下:

builder.RegisterType<NewsletterService>()
            .As<INewsletterService>()
            .InstancePerRequest();

builder.RegisterGeneric(typeof(GenericRepository<>))
            .AsSelf()
            .As(typeof(IRepository<>))
            .InstancePerLifetimeScope();
builder.RegisterType<TestUnitOfWork>().AsSelf().InstancePerRequest();
builder.RegisterType<TestUnitOfWork2>().AsSelf().InstancePerRequest();
builder.RegisterType<UniqueDatabaseFactory>().As<IDatabaseFactory>().InstancePerLifetimeScope();

到目前为止的结果 当将UnitOfWork用作InstancePerRequest时,我们得到了很好的结果,但是效果不是很好。 IDatabaseContext在拥有服务的UnitOfWork的所有实例之间共享。其他使用autofac的注册方法似乎为每次使用创建IDatabaseFactory的新实例。注册时使用InstancesPerLifetimeScope。

工作(但感觉不正确)的解决方案

另一种方法是,此方法有效,但是对于依赖项注入来说是一种新方法,感觉像是通过解决依赖项而与Autofac试图做的事情相反。

builder.Register(c =>
{
    IDatabaseFactory factory = c.Resolve<IDatabaseFactory>();
    GenericRepository<ContactSubscription> repo = c.Resolve<GenericRepository<ContactSubscription>>(
        new NamedParameter("factory", (object)factory));

    return new TestUnitOfWork(factory, repo);
}).AsSelf().InstancePerLifetimeScope();

我强烈感觉上面的解决方案不是理想的(我对loc容器的了解很少),而不是让自己陷入困境,我想看看是否有更有效的方法来拥有IDatabaseFactory由Autofac构造,以便UnitOfWork将相同的实例向下传递到存储库,但不为其他UnitOfWork保留相同的实例。

我的项目现在很混乱,因此希望示例代码没有我错过的任何错别字或旧变量。谢谢!

1 个答案:

答案 0 :(得分:0)

休息片刻后,我找到了解决问题的方法。由于UnitOfWork已经在抽象数据库上下文,并且UnitOfWork是注入的依赖项,因此现在每个UnitOfWork控制每个存储库的创建和生存期。不必注入存储库。

这是我的解决方法:

public interface INewsletterUnitOfWork
{
    IRepository<Newsletter> NewsLetters { get; }
    IRepository<ContactSubscription> ContactSubscriptions { get; }
}

public class NewsletterUnitOfWork : UowBase, INewsletterUnitOfWork
{
    private IRepository<Newsletter> _newsletters;
    public IRepository<Newsletter> NewsLetters
    {
        get { return _newsletters ?? (_newsletters = new GenericRepository<Newsletter>(Context)); }
        private set { _newsletters = value; }

    }
    private IRepository<ContactSubscription> _contactSubscriptions;
    public IRepository<ContactSubscription> ContactSubscriptions
    {
        get { return _contactSubscriptions ?? (_contactSubscriptions = new GenericRepository<ContactSubscription>(Context)); }
        private set { _contactSubscriptions = value; }

    }

    public NewsletterUnitOfWork(IDatabaseFactory factory)
        : base(factory)
    { }
}

注册很好,简单,干净。

        builder.RegisterType<DefaultDatabaseFactory>().As<IDatabaseFactory>().InstancePerLifetimeScope();

        builder.RegisterType<NewsletterUnitOfWork>()
            .AsSelf()
            .As<INewsletterUnitOfWork>()
            .InstancePerLifetimeScope();