LightCore ServiceLocator с многократной регистрацией по одному контракту

Мы пытаемся интегрировать LightCore в качестве локатора сервисов по умолчанию в нашу платформу метаданных/ORM. Поэтому нам нравится использовать некоторые регистрации по умолчанию внутри Framework, которые пользователь Framework (= разработчик приложения) может каким-то образом «переопределить» своими собственными реализациями (если ему вообще нравится это делать). Как это сделать с контейнерами IoC LightCore или другими контейнерами IoC?

Что мы пробовали:

var builder = new ContainerBuilder();
builder.Register<Foo>().ControlledBy<SingletonLifecycle>();
builder.Register<Foo, Foo2>().ControlledBy<SingletonLifecycle>();

var container = builder.Build();

var foo = container.Resolve<Foo>();

Мы зарегистрировали два класса в качестве контракта для Foo. С приведенным выше кодом мы всегда возвращаем первые (экземпляры Foo). Так что тут без преувеличения. Кстати: нам нравится получать экземпляр Foo2.

Мы изменили его с использования конкретных классов на использование интерфейсов:

var builder = new ContainerBuilder();
builder.Register<IFoo, Foo>().ControlledBy<SingletonLifecycle>();
builder.Register<IFoo, Foo2>().ControlledBy<SingletonLifecycle>();

var container = builder.Build();

var foo = container.Resolve<IFoo>();

При этом мы получаем исключение разрешения в Resolve‹>(), сообщающее, что регистрация не найдена. Если мы удалим второй оператор «Register()», он будет работать так же, как мы получим экземпляр Foo.

Мы не уверены, что пропустили некоторые общие понятия. Работает ли это с другими IoC таким же образом? Каков рекомендуемый способ отмены/отмены регистрации?

Любая помощь по этой теме была бы здоровой - не только для LightCore.

Обновление: я настроил несколько тестов для описанного выше сценария, используя IoC-контейнер SimpleInjector. С этим контейнером нужно указать AllowOverridingRegistration = true в конструкторе, и он будет работать как положено. Таким образом, похоже, что LightCore просто не поддерживает этот вариант использования должным образом, но другие поддерживают.

Обновление: мы получили быстрый ответ от создателя LightCore, в котором говорилось, что LigtCore вообще не поддерживает переопределение регистрации. Таким образом, кажется, что нет способа решить эти сценарии, переопределяя регистрацию с помощью LightCore, поэтому мы переключились с LightCore на SimpleInjector.

Следующая конфигурация SimpleInjector соответствует нашим четырем текущим требованиям:

  // Register concrete class for FooFoo
  container.RegisterSingle<FooFoo>();

  // Register concrete classes for Foo - Final registration should return FooFoo, not Foo
  container.RegisterSingle<Foo>();
  container.RegisterSingle<Foo, FooFoo>();

  // Register interfaces for IFoo - Final registration should return FooFoo, not Foo
  container.RegisterSingle<IFoo, Foo>();
  container.RegisterSingle<IFoo, FooFoo>();

  // Register list of Plugs
  container.RegisterAll(new IPlug[] { new PlugA(), new PlugB() });

Привет, Марк




Ответы (1)


Насколько я знаю, все крупные DI-фреймворки (Autofac, Unity, Castle Windsor, StructureMap, Ninject) имеют функции переопределения регистраций. Большинство из них разрешают это, выполняя несколько регистраций для одного и того же типа службы, и они выбирают одну из регистраций в качестве регистрации по умолчанию. Однако какой экземпляр они выбирают, зависит от фреймворка. В то время как некоторые фреймворки выбирают первую из нескольких регистраций, другие выбирают последнюю регистрацию. Важно знать, как это делает выбранная структура, поскольку от этого зависит, следует ли вам регистрировать «переопределяющий» экземпляр до или после всех остальных.

Поскольку все эти фреймворки имеют разное разрешение перегрузки, я решил, что Simple Injector не имеет никакого переопределяющего поведения по умолчанию (хотя, как вы уже заметили, его можно настроить). Это упрощает переход на другой фреймворк, что было одной из целей разработки Simple Injector. Однако разрешение переопределять регистрации по умолчанию также может быть источником ошибок конфигурации, отслеживание которых может занять много времени. Поскольку с Simple Injector должно быть легко начать работу, имело смысл запретить переопределение (по умолчанию).

С Simple Injector, когда AllowOverridingRegistration включен, новая регистрация действительно заменяет предыдущую регистрацию для того же типа. Это отличается от других контейнеров, которые обычно сохраняют другие регистрации и позволяют обрабатывать все эти регистрации как единую коллекцию. С Simple Injector набор вещей должен быть зарегистрирован отдельно и может быть переопределен отдельно.

Про все остальные контейнеры, кроме Simple Injector и больших, ничего сказать не могу. Тем не менее, я думаю, что переопределение будет трудно сделать с большинством из них.

person Steven    schedule 27.03.2012
comment
Мы заменили контейнер LightCore по умолчанию на SimpleInjector, и, похоже, пока он удовлетворяет наши потребности. ;) - person Marc; 27.03.2012
comment
Взгляните на этот вопрос: stackoverflow.com/questions/9852407/. И посмотрите, как это делает Enterprise Library. По умолчанию используется Unity, но контейнер можно поменять местами. - person Steven; 27.03.2012