4

Я пытаюсь переключиться на Простой инжектор Инъекционная система зависимости, поскольку меня впечатляет ее скорость.Простой инжектор с несколькими ограниченными DbContexts - исключение «IDbContext уже зарегистрирован»

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, он отлично работает - хранилища вводятся, данные вытягиваются и т. д.

Однако, я хотел бы также использовать ограниченные контексты с меньшим числом DbSets в каждом из них (Shrink EF Models with DDD Bounded Contexts), как мой код-первых 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 Message = Тип IDbContext уже зарегистрирован и контейнер в настоящее время не настроен на разрешение перекрывая регистрацию. Чтобы разрешить отмену текущей регистрации, установите для параметра Container.Options.AllowOverridingRegistrations значение true. Источник = SimpleInjector StackTrace: в SimpleInjector.Container.ThrowWhenTypeAlreadyRegistered (тип Type) в SimpleInjector.Container.AddRegistration (тип ServiceType, регистрация регистрации) на SimpleInjector.Container.Register [TService, TImplementation] (Стиль жизни, образ жизни Струнный serviceTypeParamName , String implementationTypeParamName) на SimpleInjector.Container.Register [TService, TImplementation] (Стиль жизни образ жизни) на SimpleInjector.SimpleInjectorWebExtensions.RegisterPerWebRequest [TService, TImplementation] (Container контейнер)

Если я следовать предложению:

container.Options.AllowOverridingRegistrations = true; 

, тогда DbContext2, кажется, переопределяет DbContext1, например. DbSet «Цвет» в DbContext1 и он не доступен больше:

Additional information: The entity type Colour is not part of the model for the current context. 

Как следует использовать простой Инжектор и ограниченные DbContexts вместе?

[UPDATE]

В DbContexts которые не используются в контроллерах непосредственно, они являются зависимостями хранилищ, которые просто 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 (с другим набором объектов)

Я не вижу причины, по которой невозможно использовать интерфейс IDbContext (или базовый тип) для DbContext1 и DbContext2.

Единство может сделать это:

container.RegisterType<IDbContext, NorthwindContext>(new PerRequestLifetimeManager(), "NorthwindContext"); 
container.RegisterType<IDbContext, NorthwindCustomerContext>(new PerRequestLifetimeManager(), "NorthwindCustomerContext"); 

Ninject может это сделать.

Простые указатели на инжектор CompositeLogger - может быть, можно было бы сделать трюк?

https://simpleinjector.org/

+0

Какое поведение вы ожидали? Когда вы делаете две регистрации для одного и того же типа, которые нужно вводить? Простой инжектор препятствует вам делать неоднозначную регистрацию и, следовательно, бросает. Чего вы пытаетесь достичь? Какую оспаривание нужно вводить при каких обстоятельствах? – Steven

+0

Я хотел бы как-то зарегистрировать DbContext1 и DbContext2, поскольку они включают подмножества наборов данных. Они используются репозиториями, поэтому, когда я вставляю репозиторий в contructor: public ColoursController (репозиторий IColourRepository), я ожидаю, что он сможет использовать DbContext1. public class ColourRepository: репозиторий , IColourRepository {public ColourRepository (контекст IDbContext): base (context) {} – AFD

+0

@ADNow Вы попробовали это?var webLifestyle = новый WebRequestLifestyle(); container.Register (webLifestyle); container.Register (webLifestyle); – Spock

ответ

5

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 кошмаром для обслуживания и очень подвержен ошибкам.

+0

Привет, Стивен, я знаю, что вы - гуру по этому вопросу, каков рекомендуемый способ избежать основной проблемы, которую вы упомянули в конце? – AFD

+0

@ADNow: Как я уже упоминал в своем ответе, решение состоит в том, чтобы реорганизовать далеко не двусмысленность. Это может быть так же просто, как добавить (пустой) интерфейс «ICustomerDbContext», который наследуется от «IDbContext». – Steven

+0

Ну ладно, спасибо. не был рекомендован общедоступный ColourRepository (контекст ICustomerDbContext) – AFD

Смежные вопросы