Архитектура без локатора служб с расширением Ninject WCF

#.net #ninject #service-locator

#.net #ninject #service-locator

Вопрос:

Я, наконец, получил некоторое представление о том, как Ninject обрабатывает DI, но столкнулся со следующей проблемой:

Давайте рассмотрим, что у нас есть класс, который принимает два объекта WCF ServiceHost в качестве параметров конструктора:

 public ActivitySinkServer(IDataProvider dataProvider, ServiceHost posClients, ServiceHost activitySinkOperatorClients)
  

Сначала у меня была только одна зависимость ServiceHost, поэтому я легко обработал привязку следующим образом:

 public class CommunicationModule: NinjectModule
{
public override void Load()
        {
            Bind<POSClient>().ToSelf().WithConstructorArgument("posManager", Kernel.Get<POSManager>());

            this.Bind<ServiceHost>().ToMethod(ctx => ctx.Kernel.Get<NinjectServiceHost>(new ConstructorArgument("singletonInstance", c => c.Kernel.Get<POSClient>())));
        }
}
  

В этом сценарии мой ActivitySinkServer мог бы разрешить его ServiceHost зависимость с помощью NinjectServiceHost , инициализированного одноэлементным объектом.

Теперь, когда у меня есть две зависимости ServiceHost, как я могу указать Ninject, какую из них передавать в какой параметр конструктора, все еще имея мой внутренний код, о котором Ninject не знает. (Я знаю, что мог бы использовать атрибуты Ninject и другие материалы из руководства).

Обновить:

Я пошел дальше и просто использовал

 .When(request => request.Target.Name == "posClients");
.When(request => request.Target.Name == "activitySinkOperatorClients");
  

чтобы явно указать имена переменных целевого конструктора. Не вижу в этом никакого вреда. Однако, если у кого-то есть более элегантный и объектно-ориентированный подход — вы можете ответить.

Ответ №1:

Способ, которым вы это делаете, на 100% хорош; более «элегантный» способ сделать это — использовать именованные привязки или метаданные.

Кстати, в этом случае гораздо лучше не использовать singletonInstance конструктор ServiceHost , потому что, если вы инициализируете его таким образом, WCF не позволит вам использовать какой-либо другой режим создания экземпляра (например, PerCall ). Пусть Ninject и WCF обрабатывают создание экземпляра и вместо этого используют конструктор на основе типов.

Примером именованной привязки может быть:

 class ServiceModule : NinjectModule
{
    public override void Load()
    {
        Bind<ServiceHost>().To<NinjectServiceHost>().Named("POS")
            .WithConstructorArgument("serviceType", typeof(PosService))
            .WithConstructorArgument("baseAddresses", new Uri[0]);

        Bind<ServiceHost>().To<NinjectServiceHost>().Named("ActivitySink")
            .WithConstructorArgument("serviceType", typeof(ActivitySink))
            .WithConstructorArgument("baseAddresses", new Uri[0]);
    }
}

public class Server
{
    private readonly ServiceHost posHost;
    private readonly ServiceHost activitySink;

    public Server(IDataProvider dataProvider,
        [Named("POS")] posHost,
        [Named("ActivitySink")] activitySink)
    {
        this.posHost = posHost;
        this.activitySink = activitySink;
    }
}
  

Обратите внимание, что инициализация baseAddresses аргумента конструктора необходима Ninject для выбора правильной перегрузки. Ее new Uri[0] конкретная инициализация просто приводит к тому, что по умолчанию выполняется поиск app.config базовых адресов, поэтому не беспокойтесь о передаче пустого массива.

Хотя это связывает ваш Server класс с самим Ninject, обычно ваши ServiceHost экземпляры создаются в двоичном файле приложения, а не в библиотеке, поэтому связь не является проблемой.

Я предпочитаю этот подход When синтаксису, потому что он с меньшей вероятностью сломается во время рефакторинга. Не исключено, что кто-нибудь однажды решит изменить имена параметров конструктора, и нет никаких визуальных указаний на то, что что-либо зависит от этих имен, и нет никакого способа для автоматического рефакторинга Visual Studio обнаружить эту зависимость.

Итак, ИМО, здесь лучше сделать зависимость явной, используя атрибуты; таким образом, если кто-то решит добавить третий узел службы позже, они сразу узнают, что им нужно добавить атрибут и обновить соответствующий модуль Ninject.