我目前正在使用依赖项注入(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保留相同的实例。
我的项目现在很混乱,因此希望示例代码没有我错过的任何错别字或旧变量。谢谢!
答案 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();