Dan Rigsby – Coding Up Style

Developer.Speaker.Blogger

ObservableServiceHost – An InstanceContext creation aware WCF ServiceHost

Posted by Dan Rigsby on August 20th, 2008

On the MSDN Forums for WCF recently, an enhancement request was proposed to add an event to the ServiceHost class that is fired when a new instance of the service is created.  The proposed event would look something like this:
 
ServiceHost host = new ServiceHost(typeof(MyService));
host.Open();
host.InstanceCreated += new EventHandler<InstanceEventArgs>(host_InstanceCreated);
 
It was decided that this may not be the best enhancement request since this could be done today with the extension mechanisms built into WCF.  The usefulness of the event is also dependent on the type of InstanceContextMode used:
  1. PerCall: Every call made to the endpoints would create a new service instance.  This could be useful.
  2. PerSession: Every new client connection would create a new service instance for the life of the client’s session. This could be very useful.
  3. Single: A service instance is created during the first call.  This is fairly useless since it is called when the single instance of the service starts, but not again.

However, I accepted the challenge to come up with an implementation of this extension.  What I came up with is called ObservableServiceHost.  This is a custom ServiceHost that you can use instead of the default System.ServiceModel.ServiceHost.  The solution requires only 4 files:

1. InstanceEventArgs

A simple EventArgs class is needed as a container for the InstanceContext.

public class InstanceEventArgs : EventArgs
{
    public InstanceContext InstanceContext
    {
        get;
        set;
    }

    public InstanceEventArgs()
    {
    }

    public InstanceEventArgs(
        InstanceContext instanceContext)
    {
        InstanceContext = instanceContext;
    }
}
 

2. ObservableServiceHost

ObservableServiceHost extends the functionality of a ServiceHost.  This class consists of the following:

  • A new event called InstanceCreated which uses the InstanceEventArgs.
  • Re-implemented constructors of the base ServiceHost class.
  • When the ServiceHost is Opened, a custom IEndpointBehavior is added to each of the endpoints used at the time the service is opened.  Endpoints which implement IMetadataExchange are be ignored though since the event doesn’t need to be fired a new metadata instance is created. (You could potentially modify this to add a different behaviors for different service interfaces.)
public class ObservableServiceHost : ServiceHost
{
    public event EventHandler<InstanceEventArgs> InstanceCreated;

    protected internal virtual void OnInstanceCreated(
        InstanceContext instanceContext)
    {
        EventHandler<InstanceEventArgs> handler = InstanceCreated;
        if (handler != null)
        {
            handler(this, new InstanceEventArgs(instanceContext));
        }
    }

    public ObservableServiceHost(
        object singletonInstance,
        params Uri[] baseAddresses) : base(singletonInstance, baseAddresses)
    {
    }

    public ObservableServiceHost(
        Type serviceType,
        params Uri[] baseAddresses) : base(serviceType, baseAddresses)
    {
    }

    protected override void OnOpening()
    {
        AddInstanceContextInitializers();

        base.OnOpening();
    }

    private void AddInstanceContextInitializers()
    {
        foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
        {
            if (endpoint.Contract.ContractType != typeof(IMetadataExchange))
            {
                endpoint.Behaviors.Add(new InstanceCreationEndpointBehavior(this));
            }
        }
    }
}

3. InstanceCreationInitializer

This is a basic implementation of IInstanceContextInitializer which can be used to inspect the InstanceContext when an instance is created.  This class consists of the following:

public class InstanceCreationInitializer : IInstanceContextInitializer
{
    private ObservableServiceHost m_ObservableServiceHost;

    #region IInstanceContextInitializer Members
    public void Initialize(
        InstanceContext instanceContext,
        Message message)
    {
        if (m_ObservableServiceHost != null)
        {
            m_ObservableServiceHost.OnInstanceCreated(instanceContext);
        }
    }
    #endregion IInstanceContextInitializer Member

    public InstanceCreationInitializer(
        ObservableServiceHost observableServiceHost)
    {
        m_ObservableServiceHost = observableServiceHost;
    }
}

4. InstanceCreationEndpointBehavior

This class implements IEndpointBehavior which is used to extend the runtime behavior of an endpoint and add our InstanceCreationInitializer to the endpoint dispatcher.  It is this behavior that we add to each of the endpoints when the ObservableServiceHost opens.

This class consists of the following:

  • A constructor that takes in a reference to the ObservableServiceHost and creates an instance of the InstanceCreationInitializer.
  • An implementation of IEndpointBehavior.ApplyDispatchBehavior which adds our InstanceCreationInitializer to the endpoint dispatchers InstanceContextInitializers collection.  This will cause our InstanceCreationInitializer to be run when a new instance is created.  The InstanceCreationInitializer  in turn calls our InstanceCreated event on the ObservableServiceHost.
public class InstanceCreationEndpointBehavior : IEndpointBehavior
{
    private InstanceCreationInitializer m_InstanceCreationInitializer;

    #region IEndpointBehavior Members

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.DispatchRuntime.InstanceContextInitializers.Add(
            m_InstanceCreationInitializer);
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
    #endregion IEndpointBehavior Members

    public InstanceCreationEndpointBehavior(
        ObservableServiceHost observableServiceHost)
    {
        m_InstanceCreationInitializer = new InstanceCreationInitializer(observableServiceHost);
    }

}

Example Service

Included in the code for this article is an example of how to use this library.  You can take any new or existing service and use it with the ObservableServiceHost, then just attach to the InstanceCreated event:

static class Program
{
    static void Main(string[] args)
    {
        ObservableServiceHost serviceHost = new ObservableServiceHost(
            typeof(MyService));
        serviceHost.Open();
        serviceHost.InstanceCreated += new EventHandler<InstanceEventArgs>(serviceHost_InstanceCreated);

        Console.WriteLine("Press any key to exit application...");
        Console.WriteLine();
        Console.ReadLine();

        serviceHost.Close();
    }

    static void serviceHost_InstanceCreated(object sender, InstanceEventArgs e)
    {
        Console.WriteLine("New InstanceContext created");
    }
}
 
For this sample, we are just outputting a string every time a new IntanceContext is created (You could have this do more meaningful work). Now use the WcfTestClient or any other custom client to hit the endpoint (http://localhost:8080/MyService/).  When operations are run on the service, the “New InstanceContext created” message is written to the console:

TestServer

You can play around with the InstanceContextMode on the Service to see what happens when you use it with PerCall, PerSession, or Single.  The line of code to look for is:

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]

 

I hope others find this class useful or at least have learned more about the extensibility that WCF has to offer. You can download the complete library and sample server here: http://www.danrigsby.com/Files/Rigsby.ServiceHostCreation.zip

kick it on DotNetKicks.com

4 Responses to “ObservableServiceHost – An InstanceContext creation aware WCF ServiceHost”

  1. Dew Drop - August 21, 2008 | Alvin Ashcraft's Morning Dew Says:

    [...] ObservableServiceHost – An InstanceContext Creation-Aware WCF ServiceHost (Dan Rigsby) [...]

  2. Vrana Says:

    Good job. This is very useful and used aspect wcf for me

  3. Dan Rigsby » Using IContextChannel Extensions to Store Custom Data Says:

    [...] We have looked at a couple of the extensions points on this blog in the past (ObservableServiceHost & Extending InstanceContext). Another extension point is an IContextChannel Extension. This [...]

  4. serge Says:

    Could this sample be used to identify your service instance creation load in order to properly adjust instance number parameter more accurate ?

    Then what about having the same event when instance is going to be destoyed ? would it be possible

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>