我使用实体框架6开发Web应用程序,并且在设计应用程序结构时遇到了困难。我的主要问题是如何在我的特定情况下处理依赖注入。
以下代码是我希望应用程序的外观。我使用的是Autofac,但我想这对每个DI用户来说都是基本的理解:
public interface IUnitOfWork
{
bool Commit();
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
private DbContext _context;
public UnitOfWork(DbContext context)
{
_context = context;
}
public bool Commit()
{
// ..
}
public bool Dispose()
{
_context.Dispose();
}
}
public class ProductsController : ApiController
{
public ProductsController(IProductsManager managet)
}
public class ProductsManager : IProductsManager
{
private Func<Owned<IUnitOfWork>> _uowFactory;
private IProductsDataService _dataService;
public Manager(Func<Owned<IUnitOfWork>> uowFactory, IProductsDataService dataService)
{
_dataService = dataService;
_uowFactory = uowFactory;
}
public bool AddProduct(ProductEntity product)
{
using (ownedUow = _uowFactory())
{
var uow = ownedUow.Value;
var addedProduct = _dataService.AddProduct(product);
if (addedProduct != null)
uow.Commit();
}
}
}
public interface IProductsDataService
{
ProductEntity AddProduct (Product product)
}
public class ProductsDataService : IProductsDataService
{
private IRepositoriesFactory _reposFactory;
public DataService(IRepositoriesFactory reposFactory)
{
_reposFactory = reposFactory;
}
public ProductEntity AddProduct(ProductEntity product)
{
var repo = reposFactory.Get<IProductsRepository>();
return repo.AddProduct(product);
}
}
public interface IRepositoriesFactory
{
T Get<T>() where T : IRepository
}
public class RepositoriesFactory : IRepositoriesFactory
{
private ILifetimeScope _scope;
public RepositoriesFactory(ILifetimeScope scope)
{
_scope = scope;
}
public T Get<T>() where T : IRepository
{
return _scope.Resolve<T>();
}
}
public interface IProductsRepository
{
ProductEntity AddProduct(ProductEntity);
}
public ProductsRepository : IProductsRepository
{
private DbContext _context;
public ProductsRepository(DbContext context)
{
_context = context;
}
public ProductEntity AddProduct(ProductEntity)
{
// Implementation..
}
}
这是我觉得理想的实现,但是我不知道如何实现这一点,因为我的ProductsDataService是单例,因此它与工厂工厂单元创建的Owned范围无关。 有没有办法可以将要创建的存储库关联起来,并将与工作单元创建的DbContext相同的DbContext接受?以某种方式更改RepositoriesFactory中的代码?
目前我所拥有的是工作单元包含存储库工厂,以便存储库中的上下文与工作单元中的上下文相同(我按照范围注册DbContext), 目前管理员也负责DataService的工作,我不喜欢。
我知道我可以将UnitOfWork - 方法注入传递给DataService方法,但我更倾向于使用Ctor注入,因为在我看来它看起来更好。
我想要的是分离这个 - 一个管理者,它的工作是实例化工作单元并在需要时提交它们,以及另一个实际执行逻辑的类(DataService)。
无论如何,如果您有任何改进意见/想法,我想听听您对此实施的意见。
谢谢你的时间!
编辑:这就是我最终的结果:
public interface IUnitOfWork
{
bool Commit();
}
public class DatabaseUnitOfWork : IUnitOfWork
{
private DbContext _context;
public DatabaseUnitOfWork(DbContext context)
{
_context = context;
}
public bool Commit()
{
// ..
}
}
// Singleton
public class ProductsManager : IProductsManager
{
private Func<Owned<IProductsDataService>> _uowFactory;
public ProductsManager(Func<Owned<IProductsDataService>> uowFactory)
{
_uowFactory = uowFactory;
}
public bool AddProduct(ProductEntity product)
{
using (ownedUow = _uowFactory())
{
var dataService = ownedUow.Value;
var addedProduct = _dataService.AddProduct(product);
if (addedProduct != null)
uow.Commit();
}
}
}
public interface IProductsDataService : IUnitOfWork
{
ProductEntity AddProduct (Product product)
}
public class ProductsDataService : DatabaseUnitOfWork, IDataService
{
private IRepositoriesFactory _reposFactory;
public DataService(IRepositoriesFactory reposFactory)
{
_reposFactory = reposFactory;
}
public ProductEntity AddProduct(ProductEntity product)
{
var repo = _reposFactory .Get<IProductsRepository>();
return repo.AddProduct(product);
}
}
public interface IRepositoriesFactory
{
Get<T>() where T : IRepository
}
public class RepositoriesFactory : IRepositoriesFactory
{
private ILifetimeScope _scope;
public RepositoriesFactory(ILifetimeScope scope)
{
_scope = scope;
}
public Get<T>() where T : IRepository
{
return _scope.Resolve<T>();
}
}
public interface IProductsRepository
{
ProductEntity AddProduct(ProductEntity);
}
public ProductsRepository : IProductsRepository
{
private DbContext _context;
public ProductsRepository(DbContext context)
{
_context = context;
}
public ProductEntity AddProduct(ProductEntity)
{
// Implementation..
}
}
答案 0 :(得分:4)
您不希望在单例实例中使用单例DbContext
。这没关系,可以在工厂完成。此外,您想要分享此DbContext
。这也没关系,您可以在工厂解决并返回DbContext
相关的续航时间。 问题是;您希望在单个实例中共享非单例DbContext
而不管理生命周期(Tcp / Ip请求)。
ProductService
和ProductManager
是单身人士的原因是什么?
我建议您在每个lifetimescope上使用ProductService
和ProductManager
。当你有http请求它没关系。当您有tcp / ip请求时,您可以开始新的生命周期范围(尽可能为最高级别),然后在那里解析ProductManager
。
更新:我在评论中提到的解决方案1的代码。
Managers
必须是单身人士(正如你所说)。
除managers
以外,您应将dbcontext
,services
,repositories
和Uow
注册为per lifetime
范围。
我们可以这样宣传:
public class ProductsManager : IProductsManager
{
//This is kind of service locator. We hide Uow and ProductDataService dependencies.
private readonly ILifetimeScope _lifetimeScope;
public ProductsManager(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
}
}
但这是一种服务定位器。我们隐藏了Uow
和ProductDataService
个依赖关系。
所以我们应该实现一个提供者:
public IProductsManagerProvider : IProductsManager
{
}
public class ProductsManagerProvider : IProductsManagerProvider
{
private readonly IUnitOfWork _uow;
private readonly IProductsDataService _dataService;
public ProductsManagerProvider (IUnitOfWork uow, IProductsDataService dataService)
{
_dataService = dataService;
_uow = uow;
}
public bool AddProduct(ProductEntity product)
{
var result=false;
var addedProduct = _dataService.AddProduct(product);
if (addedProduct != null)
result=_uow.Commit()>0;
return result;
}
}
我们将其注册为per dependency
(因为我们会将其用于工厂)。
container.RegisterType<ProductsManagerProvider>().As<IProductsManagerProvider>().InstancePerDependency();
你的ProductsManager
课应该是这样的。 (现在我们不隐藏任何家属)。
public class ProductsManager : IProductsManager
{
private readonly Func<Owned<IProductsManagerProvider>> _managerProvider;
//Now we don't hide any dependencies.
public ProductsManager(Func<Owned<IProductsManagerProvider>> managerProvider)
{
_managerProvider = managerProvider;
}
public bool AddProduct(ProductEntity product)
{
using (var provider = _managerProvider())
{
return provider.Value.AddProduct(product);
}
}
}
我已经用我自己的课程进行了测试。
你有一个单独的经理实例,它有一个工厂来创建经理提供者。管理器提供程序是依赖的,因为每次我们都应该在单例中获取新实例。每个生命周期中提供程序中的所有内容,因此它们的生命周期是每个依赖生存期的连接提供程
当您在经理Container
中添加产品时,会创建1 Provider
,1 DbContext
,1 DataService
和1 Uow
(DbContext
已共享) 。在Provider
中的方法返回后,Manager
与所有已重新发布的实例(DbContex,Uow,DataService)一起(依赖于)。
答案 1 :(得分:2)
似乎问题并不是确保注入UnitOfWork
和ProductsRepository
的DbContext实例是相同的。
这可以通过在解析InstancePerLifetimeScope
和LifetimeScope
之前将DbContext注册为IUnitOfWork
并创建新的ProductsRepository
来实现。
任何非您拥有的依赖关系将在处置LifetimeScope
时被处置。
问题似乎是你在这两个班级之间没有明确的关系。您的UoW并不依赖于任何DbContext&#39;,它取决于当前事务中涉及的DbContext。那个特定的。
您的UoW和存储库之间也没有直接关系。这看起来不像UoW pattern。
我无法弄清楚谁将展开IRepository
创建的IRepositoryFactory
。您正在使用容器来解决它(通过注入ILifetimeScope
的{{1}})。除非从RepositoriesFactory
获得该实例的任何人处置它,否则只能通过将Factory
注入LifetimeScope
来处理它。
可能出现的另一个问题是DbContext的所有权。您可以通过IRepositoryFactory
上的Dispose将其置于using
块上。但是您的IUnitOfWork
也没有拥有该实例。容器呢。存储库是否也会尝试处理DbContext?他们还通过构造函数注入接收。
我建议重新考虑这个解决方案。