使用DI /抽象工厂模式时处理依赖关系

时间:2012-06-28 09:57:30

标签: 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 
{
    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
}

我正在努力研究如何使用DI和抽象工厂模式来实现我想要的。在MVC应用程序中,这很容易设置 - Controller需要在其构造函数中实现IUnitOfWork和ICarsRepository的实现。我可以使用不同的控制器工厂配置容器,以便为每个Http请求提供相同的DataContext实例。不知怎的,这里似乎正确处理了一次性依赖。

但是我想在Windows服务中使用相同的存储库。这是多线程的,每个线程在启动时都需要访问自己的存储库,每个线程都应该有自己的DataContext / UnitOfWork。但我不知道该怎么做:

  • 应用程序的复合根是在服务启动时,因此无法为每个线程解析依赖关系(线程是按需启动的)。
  • 我不确定如何使用抽象工厂模式。该线程需要IUnitOfWork和ICarsRepository的实例,但共享相同的DataContext。我可以创建一个抽象工厂来在一次调用中创建它们,并将它传递给线程,但后来我不知道如何处理DataContext。我不希望线程必须关心ICarsRepository实现的依赖性是否是一次性的。我绝对不希望线程知道ICarsRepository对DataContext有依赖性,因为接口看起来毫无意义 - 线程可能只依赖于SqlCarsRespository。
  • 我不想让SqlCarsRepository变成一次性的,并让它处理DataContext,因为可能有其他人使用DataContext,并且它没有首先创建它。
  • 我认为我可以创建一个隐藏IUnitOfWork和ICarsRepository的CarsService(并使用抽象工厂获取实例),但我仍然不知道如何处理DataContext依赖

我正在尝试做什么的最好方法是什么?

1 个答案:

答案 0 :(得分:2)

  
    

因此无法为每个线程解析依赖关系

  

他们可以,事实上,他们应该。您应该在每个线程的开头解析一个新的对象图。不执行此操作意味着您只能使用线程安全依赖项,而在您的情况下则不然。

  
    

我不确定如何使用抽象工厂模式

  

我认为首先,尝试在您的MVC应用程序中定义您的DataContext作为每个Web请求,并在Windows服务中定义为每个生命周期范围(或您使用的容器中可用的任何内容)。在您的Windows服务中,每个线程都将获得它自己的生命周期范围。定义范围通常允许您在范围结束时放置实例。

  
    

我不希望线程必须关心ICarsRepository实现的依赖性是一次性的

  

您的主管应该关心这一点,但您的业务逻辑不应该。在启动新线程时,您必须拥有一些基础结构代码,允许开始和结束范围,以及解析和使用图形的根类型。此代码应该是组合根的一部分,因此应用程序的其余部分应该对此无动于衷。如果您使用Per Lifetime Scope(或其他一些显式生命周期)注册了某些类型,则容器将知道何时处置实例。基础结构代码只需告诉容器,范围已结束。

  
    

我不想让SqlCarsRepository一次性

  

SqlCarsRepository应该依赖于一个没有实现IDisposable的接口,在这种情况下,没有什么可以处理的。它应该是负责处理DataContext的容器,并且通过适当的注册,您可以执行此操作。

  
    

我正在尝试做什么的最好方法是什么?

  

您的设计听起来很合理,但这里还有其他一些问题,这可能会让您有更多的工作: