Так что это привлечет меня к тому, чтобы показать большую часть моей сантехники, но я постараюсь сохранить ее на минимальном минимуме, чтобы этот вопрос был простым.Как я могу разрешить декораторы для объектов, созданных фабрикой в Simple Injector
Одна из моих конечных точек API полагается на внешних поставщиков для завершения вызова. Когда пользователь отправляет запрос на эту конечную точку, он может указать, какой провайдер они хотят использовать для обработки запроса, скажем, провайдеры: Bing и Google.
Так у меня есть IProvider
интерфейса и два конкретных реализации BingProvider
и GoogleProvider
(в моем реальном API интерфейс поставщика на самом деле это общий интерфейс, но я уезжаю на дженерики, чтобы избежать этого грязнее, чем это должно быть). Мне нужно разрешить правильный поставщик на основе поля в запросе. Simple Injector не позволяет регистрировать несколько конкретных реализаций одного и того же интерфейса, поэтому я должен использовать фабрику; Я создаю один, который выглядит примерно так:
public class ProviderFactory
{
private readonly Func<string, IProvider> _Selector;
public ProviderFactory(Func<string, IProvider> selector)
{
this._Selector = selector;
}
public IProvider Get(string provider)
{
return this._Selector(provider);
}
}
зарегистрировать свою фабрику с контейнером, делая что-то вроде этого:
container.RegisterSingleton<ProviderFactory>(new ProviderFactory(provider =>
{
switch (provider)
{
case "Bing":
return container.GetInstance<BingProvider>()
case "Google":
return container.GetInstance<GoogleProvider>()
default:
throw new ArgumentOutOfRangeException("Unknown provider: " + provider);
}
}));
я проверить его. Оно работает. Фантастика.
Теперь мне нужно создать и зарегистрировать несколько декораторов для моего IProvider
. Каждая конкретная реализация IProvider
должна иметь эти декораторы, когда контейнер разрешает их. Для этого примера можно сказать, что у меня есть Decorator1
и Decorator2
, которые реализуют IProvider
. Я зарегистрирую их в контейнере следующим образом:
container.RegisterDecorator(typeof(IProvider), typeof(Decorator1), Lifestyle.Singleton);
container.RegisterDecorator(typeof(IProvider), typeof(Decorator2), Lifestyle.Singleton);
В этом проблема. Когда моя фабрика разрешает экземпляр BingProvider
или GoogleProvider
, это именно то, что я получаю. Я хочу получить экземпляр Decorator2
, который украшает экземпляр Decorator1
, который, в свою очередь, украшает любые конкретные реализации IProvider
, которые я просил. Я предполагаю, что это потому, что я специально не прошу контейнер разрешить экземпляр IProvider
, но я прошу его разрешить конкретную реализацию IProvider
.
Кажется, что я все запутался здесь, и я не уверен, что лучший способ - разрешить его.
Редактировать
Хорошо, после того, как думать об этом еще немного, я понимаю, почему декораторы никогда не будет решена. Возьмите, например, Decorator1
и BingProvider
. Оба Decorator1
и BingProvider
реализуют IProvider
, но Decorator1
не реализует BingProvider
, поэтому, когда я прошу Simple Injector разрешить экземпляр BingProvider
, он даже не может дать мне экземпляр Decorator1
. Мне нужно попросить его как-то разрешить экземпляр IProvider
, но дайте мне правильную конкретную реализацию с декораторами на месте.
Отлично, что я понимаю, но теперь я менее уверен в продолжении.
Update
На основании ответа Стивена я изменил мой завод регистрации, как это:
var bingProvider = Lifestyle.Singleton
.CreateProducer<IProvider, BingProvider>(container);
var googleProvider = Lifestyle.Singleton
.CreateProducer<IProvider, GoogleProvider>(container);
container.RegisterSingleton<ProviderFactory>(new ProviderFactory(provider =>
{
switch (provider)
{
case "Bing":
return bingProvider.GetInstance();
case "Google":
return googleProvider.GetInstance();
default:
throw new ArgumentOutOfRangeException("Unknown provider: " + provider);
}
}));
Моя новая проблема заключается в том, что, когда я бегу мой модульного тестирования для проверки контейнера тест завершается с (я должен был обработать это сообщение об ошибке, чтобы оно соответствовало моему примеру здесь, надеюсь, что это не приведет к утере перевода):
Конфигурация недействительна. Сообщалось о следующих диагностических предупреждениях:
- [Torn Lifestyle] Регистрация для IProvider карт с той же реализацией и образом жизни, что и регистрация для IProvider. Оба они сопоставляются с Decorator1 (Singleton). Это приведет к тому, что каждая регистрация будет разрешена для другого экземпляра: каждая регистрация будет иметь свой собственный экземпляр.
- [Torn Lifestyle] Регистрация для IProvider карт с той же реализацией и образом жизни, что и регистрация для IProvider. Оба они сопоставляются с Decorator2 (Singleton). Это приведет к тому, что каждая регистрация будет разрешена для другого экземпляра: каждая регистрация будет иметь свой собственный экземпляр.
Дополнительную информацию о предупреждениях см. В описании свойства Error. Пожалуйста, см. https://simpleinjector.org/diagnostics, как устранить проблемы и как подавить отдельные предупреждения.
Я не знаю много про простой инжектор. Но такая ситуация, которая у вас есть (несколько реализаций одного и того же интерфейса), является примером того, почему [Pure DI] (http://blog.ploeh.dk/2014/06/10/pure-di/) лучше, чем с использованием контейнера DI, на мой взгляд. Взгляните на [эту статью] (http://criticalsoftwareblog.com/index.php/2015/08/23/why-di-container-fail-with-complex-object-graphs /) для получения дополнительной информации об этом аргументе. –