Zulfiqar's weblog

Architecture, security & random .Net

Enabling InstanceProvider for Singleton Services

Posted by zamd on December 18, 2008


Many people like to use Dependency Injection containers (Unity, Windsor etc) to create WCF service objects and the common approach is to use WCF’s InstanceProvider extensibility hook to delegate instance creation to a DI container. By default this approach however doesn’t work for singleton services as InstanceProvider is never called. There is very simple fix to this problem which I’m going to explain in this post but first little background information.

WCF instancing revolve around following 3 objects:

 

InstanceContextProvider is very early in dispatch pipeline and has access to channel and message. This provider has the flexibility to reuse instance contexts based on either sessions or any other unique id in messages. When InstanceContextProvider returns an existing InstanceContext, dispatcher sees whether the returned InstanceContext has an active instance, if yes then that active instance gets used and InstanceProvider is never invoked. If there is no active instance then InstanceProvider is invoked to get one.

So when you configure your service’s InstanceContextMode=Single, there will always be cached instance and your provided will never be called. A simple fix is to overwrite the InstanceContext with a brand new one thus destroying the cached object.

    dispatchRuntime.SingletonInstanceContext = new InstanceContext(serviceHostBase);

This above change will result in your InstanceProvider to be called (only first time) to get the required service instance. Here is complete code.

 

    [ServiceContract]

    public interface ICalc

    {

        [OperationContract]

        int Add(int a, int b);

    }

    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]

    public class Calc : ICalc

    {

        public int Add(int a, int b)

        {

            Console.WriteLine(this.GetHashCode());

            return a + b;

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            ServiceHost h = new ServiceHost(typeof(Calc));

            h.Description.Behaviors.Add(new MyBv());

            h.Open();

            var cf = new ChannelFactory<ICalc>("*");

            cf.Open();

            var proxy = cf.CreateChannel();

            for (int i = 0; i < 10; i++)

            {

                proxy.Add(11, 2);

            }

            Console.ReadLine();

        }

    }

 

 

    public class MyBv : IServiceBehavior

    {

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)

        {

            var cd = serviceHostBase.ChannelDispatchers[0] as ChannelDispatcher;

            var dispatchRuntime = cd.Endpoints[0].DispatchRuntime;

            dispatchRuntime.SingletonInstanceContext = new InstanceContext(serviceHostBase);

            dispatchRuntime.InstanceProvider = new MyInstanceProvider();

        }

    }

    public class MyInstanceProvider : IInstanceProvider

    {

 

        public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message)

        {

            var c =  new Calc();

            return c;

        }

 

    }

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

 
%d bloggers like this: