Erweitern des Hosting mit ServiceHostFactory

Die standardmäßige ServiceHost-API für das Hosting von Diensten in Windows Communication Foundation (WCF) ist ein erweiterbarer Teil in der WCF-Architektur. Benutzer können ihre eigenen Hostklassen von ServiceHost ableiten, üblicherweise um OnOpening für die Verwendung von ServiceDescription zu überschreiben, um Endpunkte imperativ hinzuzufügen oder das Verhalten vor dem Öffnen des Diensts zu ändern.

In der selbst gehosteten Umgebung müssen Sie keine benutzerdefinierte ServiceHost-Klasse erstellen, weil Sie den Code schreiben, der den Host instantiiert, und rufen anschließend Open für den Host auf. Zwischen diesen beiden Schritten können Sie beliebige Vorgänge ausführen. Sie könnten z. B. ein neues IServiceBehavior hinzufügen:

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

Dieser Ansatz ist nicht wiederverwendbar. Der Code, der die Beschreibung bearbeitet, wird in das Hostprogramm eingefügt (in diesem Fall in die Main()-Funktion), daher ist es schwierig, diese Logik in anderen Kontexten wiederzuverwenden. Es gibt auch andere Wege, ein IServiceBehavior hinzuzufügen, die keinen imperativen Code erfordern. Sie können von ServiceBehaviorAttribute ein Attribut ableiten und es in Ihren Dienstimplementierungstyp aufnehmen, oder Sie können ein benutzerdefiniertes Verhalten konfigurierbar gestalten und es dynamisch mithilfe einer Konfiguration erstellen.

Es kann jedoch auch eine kleine Variante des Beispiels verwendet werden, um dieses Problem zu lösen. Ein Ansatz besteht darin, den Code, mit dem ServiceBehavior hinzugefügt wird, von Main() in die OnOpening-Methode einer benutzerdefinierten Ableitung von ServiceHost zu verschieben:

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

Dann können Sie innerhalb von Main() Folgendes verwenden.

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

Sie haben jetzt die benutzerdefinierte Logik in einer abstrakten Form gekapselt, die so in verschiedenen Hostimplementierungen wiederverwendet werden kann.

Es ist nicht unmittelbar einsichtig, wie diese benutzerdefinierte ServiceHost-Klasse innerhalb von IIS (Internetinformationsdiensten) oder WAS (Windows Process Activation Service) verwendet werden kann. Diese Umgebungen unterscheiden sich von einer selbst gehosteten Umgebung, weil die Hostumgebung im Namen der Anwendung ServiceHost instantiiert. Die Hostumgebungen IIS und WAS wissen jedoch nichts von Ihrer benutzerdefinierten ServiceHost-Ableitung.

ServiceHostFactory wurde dafür konzipiert, dieses Problem des Zugriffs auf Ihre benutzerdefinierte ServiceHost-Klasse durch IIS oder WAS zu lösen. Da ein benutzerdefinierter, von ServiceHost abgeleiteter Host dynamisch konfiguriert und von potentiell unterschiedlichem Typ ist, wird er von der Hostumgebung niemals direkt instantiiert. Stattdessen verwendet WCF ein Factorymuster, um eine Dereferenzierungsschicht zwischen der Hostumgebung und dem konkreten Typ des Diensts bereitzustellen. Sofern Sie nichts anderes angeben, wird dazu eine Standardimplementierung von ServiceHostFactory verwendet, die eine Instanz von ServiceHost zurückgibt. Sie können jedoch auch eine eigene Factory bereitstellen (eine, die den abgeleiteten Host zurückgibt), indem Sie den CLR-Typnamen Ihrer Factory-Implementierung in der @ServiceHost-Direktive angeben.

Ziel ist, dass in den grundlegenden Fällen die Implementierung einer eigenen Factory eine einfache Angelegenheit sein sollte. Als Beispiel folgt hier eine benutzerdefinierte ServiceHostFactory, die eine abgeleitete ServiceHost-Klasse zurückgibt:

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

Wenn Sie diese Factory statt der Standardfactory verwenden möchten, geben Sie einfach den Typnamen in der @ServiceHost-Direktive wie folgt an:

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

Zwar gibt es keine technische Grenze für das, was Sie mit einer von CreateServiceHost zurückgegebenen ServiceHost-Klasse tun können, jedoch wird empfohlen, die Implementierung der Factory so einfach wie möglich zu halten. Falls Sie benutzerdefinierte Logik großen Umfangs definieren müssen, platzieren Sie sie statt in die Factory besser in den Host, damit der Code einfacher wiederverwendet werden kann.

Es gibt noch eine weitere Ebene der Host-API, die hier erwähnt werden muss. WCF verfügt über ServiceHostBase und ServiceHostFactoryBase, von denen ServiceHost und ServiceHostFactory ableiten. Diese sind für erweiterte Szenarien vorgesehen, in denen Sie große Teile des Metadatensystems mit Ihren benutzerdefinierten Klassen auslagern müssen.