在下面的简化示例中,我有一个 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 的实例。我可以将容器配置为使用不同的 Controller 工厂为每个 Http 请求提供相同的 DataContext 实例。不知何故,这里的一次性依赖似乎被正确处理。
但是我想在 Windows 服务中使用相同的存储库。这是多线程的,每个线程在启动时都需要访问自己的存储库,每个线程都应该有自己的 DataContext/UnitOfWork。但我不知道如何做到这一点:
做我正在尝试的最佳方法是什么?
最佳答案
他们可以,事实上,他们应该。您应该在每个线程的开头解析一个新的对象图。不这样做,意味着您只能使用线程安全的依赖项,而您的情况并非如此。
我认为首先,尝试将您的 DataContext
定义为 MVC 应用程序中的 Per Web Request,以及 Windows 服务中的 Per Lifetime Scope(或您使用的容器中可用的任何内容)。在您的 Windows 服务中,每个线程都将获得自己的生命周期范围。定义范围通常允许您在范围结束时处理实例。
您的线程应该关心这一点,但您的业务逻辑不应该关心。启动新线程时,您将必须拥有一些基础结构代码,以允许启动和结束范围,以及解析和使用图的根类型。这段代码应该是你的组合根的一部分,所以应用程序的其余部分应该忽略这一点。如果您使用 Per Lifetime Scope(或其他一些显式生命周期)注册了某些类型,您的容器将知道何时处置这些实例。基础设施代码只需要告诉容器范围已经结束。
SqlCarsRepository
应该依赖于一个没有实现 IDisposable
的接口(interface),在这种情况下没有什么可以处理的。它应该是负责处理 DataContext
的容器,并且通过适当的注册您可以做到这一点。
你的设计听起来很合理,但这里有一些其他的 SO 问题,它们可能会给你更多的工作:
关于c# - 使用 DI/抽象工厂模式时的依赖处理,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11242166/