Поделиться через


Расширение хостинга с помощью ServiceHostFactory

Стандартный ServiceHost API для размещения служб в Windows Communication Foundation (WCF) — это точка расширяемости в архитектуре WCF. Пользователи могут наследовать свои классы узлов от ServiceHost, обычно переопределяя OnOpening(), чтобы использовать ServiceDescription для императивного добавления конечных точек по умолчанию или изменения поведения перед началом работы службы.

В самостоятельной среде размещения вам не нужно создавать настраиваемый ServiceHost, потому что вы пишете код, который создает экземпляр узла, а затем вызываете Open() для него после создания экземпляра. Между этими двумя шагами вы можете сделать все, что вы хотите. Например, можно добавить новое IServiceBehavior:

public static void Main()  
{  
   ServiceHost host = new ServiceHost( typeof( MyService ) );  
   host.Description.Add( new MyServiceBehavior() );  
   host.Open();  
  
   ...  
}  

Этот подход не допускает повторного использования. Код, который управляет описанием, закодирован в основную программу (в данном случае функцию Main(), поэтому ее сложно повторно использовать в других контекстах. Существуют и другие способы добавления IServiceBehavior , которые не требуют императивного кода. Вы можете вывести атрибут из ServiceBehaviorAttribute, назначив его типу реализации службы, или настроить настраиваемое поведение, компонуя его динамически с помощью конфигурации.

Однако для решения этой проблемы также можно использовать небольшой вариант примера. Одним из подходов является перемещение кода, который добавляет ServiceBehavior, из Main() в метод OnOpening пользовательского производного класса ServiceHost.

public class DerivedHost : ServiceHost  
{  
   public DerivedHost( Type t, params Uri baseAddresses ) :  
      base( t, baseAddresses ) {}  
  
   public override void OnOpening()  
   {  
  this.Description.Add( new MyServiceBehavior() );  
   }  
}  

Затем внутри Main() можно использовать следующее:

public static void Main()  
{  
   ServiceHost host = new DerivedHost( typeof( MyService ) );  
   host.Open();  
  
   ...  
}  

Теперь вы инкапсулировали пользовательскую логику в чистую абстракцию, которую можно легко повторно использовать в разных исполняемых файлах узла.

Не сразу видно, как использовать этот пользовательский ServiceHost код внутри служб IIS или службы активации процесса Windows (WAS). Эти среды отличаются от среды самостоятельного размещения, потому что именно среда размещения создает экземпляр ServiceHost от имени приложения. Инфраструктура размещения IIS и WAS не знает ничего о пользовательской производной ServiceHost .

ServiceHostFactory был разработан для решения проблемы доступа к вашему пользовательскому ServiceHost внутри IIS или WAS. Поскольку пользовательский хост, производный от ServiceHost, динамически настраивается и может быть различных типов, среда размещения никогда не создает его напрямую. Вместо этого WCF использует шаблон фабрики для предоставления слоя косвенного взаимодействия между средой размещения и конкретным типом службы. Если вы не сообщите ему в противном случае, он использует реализацию ServiceHostFactory по умолчанию, которая возвращает экземпляр ServiceHost. Но вы также можете предоставить собственную фабрику, которая возвращает производящий хост, указав в директиве @ServiceHost имя типа CLR вашей реализации фабрики.

Цель заключается в том, чтобы для основных случаев реализация собственной фабрики была простым процессом. Например, здесь представлен пользовательский ServiceHostFactory, который возвращает производное ServiceHost.

public class DerivedFactory : ServiceHostFactory  
{  
   public override ServiceHost CreateServiceHost( Type t, Uri[] baseAddresses )  
   {  
      return new DerivedHost( t, baseAddresses )  
   }  
}  

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

<% @ServiceHost Factory="DerivedFactory" Service="MyService" %>

Хотя нет технического ограничения на то, что вы хотите сделать с ServiceHost, которое вы возвращаете из CreateServiceHost, мы рекомендуем сохранить реализацию фабрики как можно проще. Если у вас много пользовательской логики, лучше поместить эту логику на хост вместо фабрики для повторного использования.

В API размещения есть еще один слой, который следует упомянуть здесь. WCF также имеет ServiceHostBase и ServiceHostFactoryBase, от которых ServiceHost и ServiceHostFactory соответственно наследуют. Они существуют для более сложных сценариев, в которых необходимо заменить большие части системы метаданных собственными настраиваемыми решениями.