Using a WCF Custom Instance Provider

I recently developed a couple of WCF services that I wanted to share some common data, which I stored to and read from an XML file using standard serialization. (I didn’t want the trouble of setting up a database and writing code to access it.) And I didn’t want to load and save this file for every service call. So what I did was to create a custom instance provider that (a) loaded data from the file each time a service was instantiated and saved each time it was released and (b) passed a reference to the shared data to the created service instance.

First I created a class that implemented IInstanceProvider:

public class MyInstanceProvider : IInstanceProvider
{
    private static List<Case> caseList = null;

    #region IInstanceProvider Members

    public object GetInstance(InstanceContext instanceContext)
    {
        if (caseList == null)
            caseList = Load();
        return new TheService(logger, caseList);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        Save();
        if (instance is IDisposable)
            ((IDisposable)instance).Dispose();
    }

    #endregion
}

To be able to use this instance provider, I then created a custom attribute using this code:

public class CustomInstancingBehaviorAttribute : Attribute, IContractBehaviorAttribute, IContractBehavior
{
    #region IContractBehaviorAttribute Members

    public Type TargetContract
    {
        get { return typeof(ITheService); }
    }

    #endregion

    #region IContractBehavior Members

    public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection parameters)
    {
        return;
    }

    public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        return;
    }

    public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime dispatch)
    {
        dispatch.InstanceProvider = new MyInstanceProvider();
    }

    public void Validate(ContractDescription description, ServiceEndpoint endpoint)
    {
        return;
    }

    #endregion
}

The important method above is ApplyDispatchBehavior that specifies that my instance provider should be used instead of the default one.

I could then use this attribute with my service implementation:

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Single)]
[CustomInstancingBehavior]
public class TheService : ITheService
{
    private Logger logger;
    private List<EcosCase> caseList;

    public TheService()
    {
    }

    public TheService(Logger logger, List<Case> caseList)
    {
        this.caseList = caseList;
    }

    …
}

The reason for specifying ConcurrencyMode.Single is that I did not want to write synchronization code to mitigate the risk that multiple threads could update the list simultaneously.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s