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:
- PerCall: Every call made to the endpoints would create a new service instance. This could be useful.
- PerSession: Every new client connection would create a new service instance for the life of the client’s session. This could be very useful.
- 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:

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
