Of Hosts and Factories

I promised in my last post on the @ServiceHost Directive that I would talk in more detail about Factory attribute in that directive and why we have it. So here goes…

The motivation for API’s that I’m going to talk about in this post stems from the fact that the standard API for hosting services in WCF (System.ServiceModel.ServiceHost) is a first-class extensibility point in the WCF architecture. We expect that lots of folks will derive their own host classes from ServiceHost, usually with the intent of overriding ServiceHost.OnOpening in order to do interesting things with the ServiceDescription (e.g. adding default endpoints imperatively, or twiddling knobs on Behaviors) prior to  opening the service.

In the self-host world, you can get away without creating a custom ServiceHost because you write the code that instantiates the host and subsequently calls Open on it. In between those two steps you can do whatever you want, e.g.:

public static void Main()

{

   ServiceHost host = new ServiceHost( typeof( MyService ) );

   host.Description.Behaviors.Add( new MyServiceBehavior() );

   host.Open();

  

   ...

}

 

Note: this is just a trivial example of futzing with the host’s Description prior to opening it. There are other ways of adding ServiceBehaviors that don’t require imperative code (e.g. you can inherit an attribute from ServiceBehaviorAttribute and stick that on your service implementation type, or you can make a custom behavior configurable and compose it in dynamically via configuration). Don’t read too much in to the above code.

However, this solution has the downside of not being particularly reusable. The code that manipulates the description is baked into the host program (in this case, the Main() function) so if you want to reuse that logic in other contexts you’ve got a little bit of a problem. A slight refactoring will solve that problem; all we have to do is 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.Behaviors.Add( new MyServiceBehavior() );

   }

}

 

Then, inside of Main() you just say

public static void Main()

{

   ServiceHost host = new DerivedHost( typeof( MyService ) );

   host.Open();

  

   ...

}

 

And you’ve now encapsulated that custom logic up into a nice, clean abstraction that can be easily reused across lots of different host executables.

What’s not immediately obvious at this point is how to use this custom ServiceHost inside of IIS or WAS. Those environments are different than the self-host world, because the hosting environment is the one instantiating the ServiceHost on behalf of the application (details on how that all works are here). The WAS hosting infrastructure doesn’t know anything about your custom ServiceHost derivative, and it seems like there’s no good place to write that new DerivedHost( typeof( MyService ) ); line when running in IIS/WAS. What’s a poor customer of the WCF extensibility model to do in this case?

This is exactly the problem that the ServiceHostFactory API was designed to solve.

Because the ServiceHost used to host the service is a potentially polymorphic type, the hosting environment never instantiates it directly. Instead, we use a factory pattern to provide a layer of indirection between the hosting environment and the concrete type of the service. Unless you tell us otherwise, we’ll use a  default implementation (System.ServiceModel.Activation.ServiceHostFactory) that simply returns an instance of System.ServiceModel.ServiceHost. You can provide your own factory (one that presumably returns your derived host) by specifying the CLR type name of your factory implementation in the @ServiceHost directive.

The intent is that for simple cases, implementing your own factory should be a trivial exercise. For example, here’s a ServiceHostFactory that returns the DerivedHost from previous examples in this post:

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, just provide the type name in the @ServiceHost directive as follows:

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

 

While there’s not technical prohibition on doing pretty much whatever you want to the ServiceHost you return from ServiceHostFactory.CreateServiceHost(), our guidance here is to keep your factory implementations as light as possible. If you have lots of custom logic, you’re better off putting that inside your host instead of inside the factory for the same reusability reasons that you don’t want to put a lot of host-related code inside of Main().

That’s about it for the mainstream use case for ServiceHost and ServiceHostFactory extensibility. People who have been actively Reflectoring over the ServiceModel .dll’s will likely notice that there’s another layer to this onion. Specifically, we also have ServiceHostBase/ServiceHostFactoryBase, from which ServiceHost and ServiceHostFactory respectively derive. Those exist for more esoteric scenarios where you want to swap out large parts of our metadata system with creations of your own devising. I’ll talk about that more next time around.

#1 Steve Maine on 7.16.2006 at 7:41 PM

No Jim, you're not crazy -- that's a typo. Thanks for pointing that out :) I fixed the code sample.