C# 使用DI/抽象工厂模式时的依赖项处理
在下面的简化示例中,我有一个DataContext和Repository,我认为它的定义相当合理:C# 使用DI/抽象工厂模式时的依赖项处理,c#,entity-framework,dependency-injection,repository-pattern,abstract-factory,C#,Entity Framework,Dependency Injection,Repository Pattern,Abstract Factory,在下面的简化示例中,我有一个DataContext和Repository,我认为它的定义相当合理: public interface IUnitOfWork { int SaveChanges(); } public class DataContext : DbContext, IUnitOfWork { public DbSet<Car> Cars { get ; set; } } public interface ICarsRepository {
public interface IUnitOfWork
{
int SaveChanges();
}
public class DataContext : DbContext, IUnitOfWork
{
public DbSet<Car> Cars { get ; set; }
}
public interface ICarsRepository
{
Car Find(int id);
void Add(Car car);
}
public class SqlCarsRepository : ICarsRepository
{
private DataContext _context;
public SqlCarsRepository(DataContext context)
{
_context = context;
}
public Car Find(int id)
{
return _context.Cars.Find(id);
}
//etc
}
公共接口IUnitOfWork
{
int SaveChanges();
}
公共类DataContext:DbContext,IUnitOfWork
{
公共数据库集车辆{get;set;}
}
公共接口ICarsRepository
{
车辆查找(int id);
无效添加(汽车);
}
公共类SqlCarsRepository:ICarsRepository
{
私有数据上下文_上下文;
公共SqlCarsRepository(DataContext上下文)
{
_上下文=上下文;
}
公共车辆查找(int id)
{
return\u context.Cars.Find(id);
}
//等
}
我正在努力研究如何使用DI和抽象工厂模式来实现我想要的。在MVC应用程序中,这将很容易设置-控制器需要在其构造函数中实现IUnitOfWork和ICarsRepository的实例。我可以配置容器,使用不同的控制器工厂为每个Http请求提供相同的DataContext实例。不知何故,这里似乎正确地处理了一次性依赖项
但是,我希望在windows服务中使用相同的存储库。这是多线程的,每个线程在启动时都需要访问自己的存储库,每个线程都应该有自己的DataContext/UnitOfWork。但我不知道怎么做:
- 应用程序的复合根是服务启动时,因此无法解析每个线程的依赖关系(线程按需启动)
- 我不确定如何使用抽象工厂模式。该线程需要IUnitOfWork和ICarsRepository的实例,但共享相同的DataContext。我可以创建一个抽象工厂,在一次调用中创建这两个函数,并将其传递到线程中,但是我不知道如何处理DataContext。我不希望线程必须关心对ICarsRepository的实现的依赖关系是一次性的。我绝对不想让线程知道ICarsRepository依赖于DataContext,因为这样看来,拥有一个接口似乎毫无意义——线程可能只依赖于SqlCarsRespository
- 我不想让SqlCarsRepository成为一次性的,并让它处理DataContext,因为可能有其他人在使用DataContext,而它一开始并没有创建它
- 我认为我可以创建一个CarsService来隐藏IUnitOfWork和ICarsRepository(并使用抽象工厂获取其实例),但我仍然不知道如何处理DataContext依赖关系
DataContext
。在windows服务中,每个线程都有自己的生存期范围。定义范围通常允许在范围结束时释放实例
我不希望线程必须关心对ICarsRepository的实现的依赖关系是一次性的
你的线程应该关心这一点,但你的业务逻辑不应该。在启动新线程时,您必须拥有一些基础结构代码,这些代码允许启动和结束作用域,以及解析和使用图的根类型。这段代码应该是合成根目录的一部分,因此应用程序的其余部分应该忽略这一点。如果使用每个生存期范围(或其他显式生存期)注册了某些类型,则容器将知道何时处置实例。基础结构代码只需告诉容器作用域已结束
我不想让SqlCarsRepository成为一次性的
SqlCarsRepository
应该依赖于一个不实现IDisposable
的接口,在这种情况下,没有什么可处理的。它应该是负责处理DataContext
的容器,通过正确的注册,您可以这样做
做我正在尝试的事情的最佳方式是什么
您的设计听起来很合理,但以下是一些其他的SO问题,这些问题可能会给您带来更多的帮助: