我正在尝试切换到 Simple Injector 依赖注入框架,因为我对它的速度印象深刻。
private static void RegisterServices(Container container)
{
container.RegisterPerWebRequest<IDbContext, DbContext1>();
////container.RegisterPerWebRequest<IDbContext, DbContext2>();
container.RegisterPerWebRequest<IUnitOfWork, UnitOfWork>();
container.RegisterPerWebRequest<IColourRepository, ColourRepository>();
其中DbContext1和DbContext2从BaseDbContext类继承
public class BaseDbContext<TContext> : DbContext, IDbContext where TContext : DbContext
实现了一个相当简单的IDbContext接口(就像SO上提供的那些接口一样),例如:
public interface IDbContext
{
IQueryable<TEntity> Find<TEntity>() where TEntity : class;
DbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
void Dispose();
}
如果我只使用一个DbContext类,它可以正常工作 - 存储库被注入,数据被拉出等。
但是,我还想在每个(Shrink EF Models with DDD Bounded Contexts)中使用带有少量DbSet的有界上下文,因为我的Code-First DbContext会包含数百个类
private static void RegisterServices(Container container)
{
container.RegisterPerWebRequest<IDbContext, DbContext1>();
container.RegisterPerWebRequest<IDbContext, DbContext2>();
container.RegisterPerWebRequest<IUnitOfWork, UnitOfWork>();
container.RegisterPerWebRequest<IColourRepository, ColourRepository>();
然后我得到一个例外:
System.InvalidOperationException未被用户代码处理 的HResult = -2146233079 消息=类型IDbContext已经注册,并且当前未将容器配置为允许覆盖注册。要允许覆盖当前注册,请将Container.Options.AllowOverridingRegistrations设置为true。 来源= SimpleInjector 堆栈跟踪: 在SimpleInjector.Container.ThrowWhenTypeAlreadyRegistered(类型类型) 在SimpleInjector.Container.AddRegistration(类型serviceType,注册注册) 在SimpleInjector.Container.Register [TService,TImplementation](Lifestyle lifestyle,String serviceTypeParamName,String implementationTypeParamName) 在SimpleInjector.Container.Register [TService,TImplementation](生活方式生活方式) 在SimpleInjector.SimpleInjectorWebExtensions.RegisterPerWebRequest [TService,TImplementation](容器容器)
如果我遵循这个建议:
container.Options.AllowOverridingRegistrations = true;
然后DbContext2似乎覆盖DbContext1,例如DbSet“Color”在DbContext1中,不再可以访问:
Additional information: The entity type Colour is not part of the model for the current context.
我应该如何一起使用Simple Injector和DbContexts?
[UPDATE]
DbContexts没有直接在控制器中使用,它们是存储库的依赖关系,Simple Injector应该能够在构造函数中初始化
public class ColoursController : ApiController
{
private readonly IColourRepository _repository;
private readonly ModelFactory _modelFactory;
public ColoursController(IColourRepository repository)
{
_repository = repository;
_modelFactory = new ModelFactory();
}
其中
public class ColourRepository : Repository<Colour>, IColourRepository
{
public ColourRepository(IDbContext context) : base(context) { }
ColourRepository期望DbContext1的具体实现,但是其他一些存储库需要DbContext2(具有不同的实体集)
我没有看到为什么不能为DbContext1和DbContext2使用IDbContext接口(或基本类型)的原因。
Unity可以做到:
container.RegisterType<IDbContext, NorthwindContext>(new PerRequestLifetimeManager(), "NorthwindContext");
container.RegisterType<IDbContext, NorthwindCustomerContext>(new PerRequestLifetimeManager(), "NorthwindCustomerContext");
Ninject可以做到。
Simple Injector提到CompositeLogger - 也许那个人可以做到这一点?
答案 0 :(得分:6)
ColourRepository期望DbContext1的具体实现,但是 其他一些存储库需要DbContext2(使用不同的一组 实体)
您的设计目前含糊不清。虽然你的设计讲的是IDbContext
,看起来如果只有一个抽象有两个实现,但这些实现是不可互换的(Liskov Substitution principle违规),这表明实际上应该有两个不同的接口。此外,只有一个界面使您的DI配置更复杂,更难维护(这与您选择的框架无关)。
因此,解决方案是通过为每个上下文提供自己的界面来消除设计中的歧义。这允许您的存储库依赖于它们所需的抽象:
public class ColourRepository : Repository<Colour>, IColourRepository
{
public ColourRepository(ICustomerDbContext context) : base(context) { }
}
这样可以简化注册:
container.Register<IDbContext, NorthwindContext>(Lifestyle.Scoped);
container.Register<ICustomerDbContext, NorthwindCustomerContext>(Lifestyle.Scoped);
请注意,使用键控注册不能解决核心问题;你仍然会被迫明确说明应该在哪个存储库中注入哪个键控版本,这将使你的DI配置成为维护的噩梦并且非常容易出错。