Rediger

Del via


Extending Hosting Using ServiceHostFactory

The standard ServiceHost API for hosting services in Windows Communication Foundation (WCF) is an extensibility point in the WCF architecture. Users can derive their own host classes from ServiceHost, usually to override OnOpening() to use ServiceDescription to add default endpoints imperatively or modify behaviors, prior to opening the service.

In the self-host environment, you do not have to create a custom ServiceHost because you write the code that instantiates the host and then call Open() on it after you instantiate it. Between those two steps you can do whatever you want. You could, for example, add a new IServiceBehavior:

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

This approach is not reusable. The code that manipulates the description is coded into the host program (in this case, the Main() function), so it is difficult to reuse that logic in other contexts. There are also other ways of adding an IServiceBehavior that do not require imperative code. You can derive an attribute from ServiceBehaviorAttribute and put that on your service implementation type or you can make a custom behavior configurable and compose it dynamically using configuration.

However, a slight variation of the example can also be used to solve this problem. One approach is to move the code that adds the ServiceBehavior out of Main() and into the OnOpening method of a custom derivative of ServiceHost:

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

Then, inside of Main() you can use:

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

Now you have encapsulated the custom logic into a clean abstraction that can be easily reused across many different host executables.

It is not immediately obvious how to use this custom ServiceHost from inside of Internet Information Services (IIS) or Windows Process Activation Service (WAS). Those environments are different than the self-host environment, because the hosting environment is the one instantiating the ServiceHost on behalf of the application. The IIS and WAS hosting infrastructure does not know anything about your custom ServiceHost derivative.

The ServiceHostFactory was designed to solve this problem of accessing your custom ServiceHost from within IIS or WAS. Because a custom host that is derived from ServiceHost is dynamically configured and potentially of various types, the hosting environment never instantiates it directly. Instead, WCF uses a factory pattern to provide a layer of indirection between the hosting environment and the concrete type of the service. Unless you tell it otherwise, it uses a default implementation of ServiceHostFactory that returns an instance of ServiceHost. But you can also provide your own factory that returns your derived host by specifying the CLR type name of your factory implementation in the @ServiceHost directive.

The intent is that for basic cases, implementing your own factory should be a straight forward exercise. For example, here is a custom ServiceHostFactory that returns a derived ServiceHost:

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

To use this factory instead of the default factory, provide the type name in the @ServiceHost directive as follows:

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

While there is no technical limit on doing what you want to the ServiceHost you return from CreateServiceHost, we suggest that you keep your factory implementations as simple as possible. If you have lots of custom logic, it is better to put that logic inside of your host instead of inside the factory so that it can be reusable.

There is one more layer to the hosting API that should be mentioned here. WCF also has ServiceHostBase and ServiceHostFactoryBase, from which ServiceHost and ServiceHostFactory respectively derive. Those exist for more advanced scenarios where you must swap out large parts of the metadata system with your own customized creations.