In my last post I had started writing about Instance Pooling in WCF and we ended up developing a simple class providing object pooling functionality.In this post we will see what needs to be done step by step to incorporate this instance pool into the WCF framework.
Implementing IInstanceProvider
The class System.Runtime.Dispatcher.DispatchRuntime exposes the property InstanceProvider of type IInstanceProvider.DispatchRuntime uses this instance to acquire and release instances of service objects.IInstanceProvider defines the following methods:
- GetInstance – Returns an service object instance
- ReleaseInstance – Releases a service object instance
I have developed a class ServiceObjectPool which implements this interface and internally talks to the object pool as shown below:
public class ServiceObjectPool:IInstanceProvider
{
private ResourcePool pool = null;
public ServiceObjectPool(Type resourceType, int maxPoolSize, int initialSize)
{
pool = new ResourcePool(resourceType, maxPoolSize, initialSize); //Create the pool
}
public ServiceObjectPool(Type resourceType, int maxPoolSize, int initialSize, int incrementSize)
{
pool = new ResourcePool(resourceType,maxPoolSize,initialSize,incrementSize); //Create the pool
}
public object GetInstance(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
{
return pool.Acquire(); //Acquire from the Pool
}
public object GetInstance(System.ServiceModel.InstanceContext instanceContext)
{
return pool.Acquire(); //Acquire from the pool
}
public void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, object instance)
{
pool.Release(instance); //Release the object back to pool
}
}
Attaching the InstanceProvider to DispatchRuntime
To attach the custom Instance Provider to DispatchRuntime I have developed a custom behavior class ServicePoolBehavior as shown below:
public class ServicePoolBehavior : IServiceBehavior
{
public int MinPoolSize { get; set; }
public int MaxPoolSize { get; set; }
public int IncrementSize { get; set; }
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
…….
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
return;
}
}
The main code goes into the ApplyDispatchBehavior method as shown below:
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
//Create the ServiceObjectPool instance
ServiceObjectPool pool = new ServiceObjectPool(serviceDescription.ServiceType,MaxPoolSize ,MinPoolSize ,IncrementSize);
ServiceThrottle throt = null;
//Change the ServiceThrottle Setting in line with the Object Pool Settings
foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers)
{
if(chDisp.ServiceThrottle!=null)
{
if (throt == null)
{
throt = chDisp.ServiceThrottle;
}
else
{
chDisp.ServiceThrottle = throt;
}
if (throt.MaxConcurrentInstances > MaxPoolSize)
{
throt.MaxConcurrentInstances = MaxPoolSize;
}
}
foreach (EndpointDispatcher endDisp in chDisp.Endpoints)
{
//Attach the Pool to Dispatch Runtime
endDisp.DispatchRuntime.InstanceProvider = pool;
}
}
}
Attaching Behavior To Host
This can be done through code,attribute or configuration.Here I chose the configuration route.To attach the service behavior through configuration we need implement a subclass of System.ServiceModel.Configuration.BehaviorExtensionElement as shown below:
public class ServicePoolBehaviorExtensionElement:BehaviorExtensionElement
{
[ConfigurationPropertyAttribute("minPoolSize",DefaultValue=2)]
[IntegerValidator(MinValue=1)]
public int MinPoolSize { get; set; }
[ConfigurationPropertyAttribute("maxPoolSize",DefaultValue=10)]
[IntegerValidator(MinValue = 1)]
public int MaxPoolSize { get; set; }
[ConfigurationPropertyAttribute("incrementSize",DefaultValue=2)]
[IntegerValidator(MinValue = 1)]
public int IncrementSize { get; set; }
public override Type BehaviorType
{
get { return typeof(ServicePoolBehavior); }
}
protected override object CreateBehavior()
{
ServicePoolBehavior behavior = new ServicePoolBehavior();
behavior.MaxPoolSize = Convert.ToInt32( this.ElementInformation.Properties["minPoolSize"].Value);
behavior.MinPoolSize = Convert.ToInt32( this.ElementInformation.Properties["maxPoolSize"].Value);
behavior.IncrementSize = Convert.ToInt32( this.ElementInformation.Properties["incrementSize"].Value) ;
return behavior;
}
}
The following lines needs to be added in the configuration file of the host:
<extensions>
<behaviorExtensions>
<add name=”poolBehavior” type=”SB.ServiceModel.Pool.ServicePoolBehaviorExtensionElement, SB.ServiceModel.Pool, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null” />
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name=”testBehavior”>
<serviceDebug includeExceptionDetailInFaults=”true” />
<serviceMetadata httpGetEnabled=”true” httpGetUrl=”http://localhost:9001/Meta” />
<poolBehavior minPoolSize=”5″ maxPoolSize=”10″ incrementSize=”2″/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration=”testBehavior” name=”SampleService.Test”>
<endpoint address=”http://localhost:9001/Test” binding=”wsHttpBinding”
name=”testhttp” contract=”SampleService.ITest” />
</service>
</services>
</system.serviceModel>
With this we complete the development of a simple pooling behavior attached to WCF service host.

