All About Instance Management in WCF

When I began learning WCF, the first thing I learned was "A service is just like another class". Okay so if WCF is just an instance of a class then what will handle the requests from the client? Confusing? Perhaps! In this article let us explore WCF Instance Management.

In WCF, Instance Management is a technique to decide which service instance will serve a client request. It also decides when a client request will be served by a service instance. Instance Management is a very important factor when designing a service. Its affects:

  • Scalability of Service
  • Performance of Service
  • Durability of Service
  • Transactions
  • Service Queues

Instance Management can be seen as a set of techniques to decide which service instance will serve a client request and when.

There are the following three kinds of Instance Management techniques:

  1. Per-Call Instance Management technique
  2. Per-Session Instance Management technique
  3. Singleton Instance Management technique

Instance Management 

Before we proceed to the details of Instance management, we need to understand Behaviors in WCF. Using Behaviors any service side implementation details can be abstracted from the client. Since Instance management is service-side behavior, its implementation details will be abstracted from the client using the service-side behaviour. Some points about Behaviors are as follows:
  • Behavior is a local attribute of service that does not affect its communication patterns.
  • The Client is not aware of the Behavior.
  • The Service does not manifest Behavior in the binding or metadata.
  • Practically Behaviors are WCF classes.
  • Behaviors are executed at runtime.

There are the following three kinds of behaviors:

  1. Service Behaviors
  2. EndPoint Behaviors
  3. Operation Behaviors

behaviors
Service Behaviors are aplied directly to a service implementation class. It affects all the EndPoints and it is used to configure Service Instance Mode. Operation Behaviors are used to configure operation behavior and it affects only an implementation of a specific operation. It could apply only to a method that implements the contract operation. It is not applied to the contract definition itself.

Now let us return to Instance Management. We use a Service Behavior to configure an Instance Mode on a WCF Service. InstanceConextMode is an enum in System.ServiceModel that is used to configure Instance mode of a service.

Enum InstanceContextMode is defined as below in System.ServiceModel.

InstanceContextMode
As we saw earlier that there are three Instance Mode techniques. These three techniques work as follows:

 
three Instance Mode techniques

Per-Call Instance mode creates a new instance for each request from the client. When the client request is served the instance is disposed of. To demonstrate the Per-Call instance technique define a service as below:
  1. [ServiceContract]  
  2.     public interface IService1  
  3.     {  
  4.         [OperationContract]  
  5.         int counter();       
  6.     }   
To expose service as using Per-Call Instance mode, the Service behavior must be configured as below:
 
Service behavior

You just need to set InstanceContextMode to InstanceContectMode.PerCall to enable the service as a Per-Call Service. To demonstrate Per-Call we have implemented a service as below:
  1. [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]  
  2.     public class Service1 : IService1,IDisposable  
  3.     {  
  4.         static int _counter = 0;   
  5.         public Service1()  
  6.         {  
  7.             _counter = _counter + 1;   
  8.         }  
  9.        public int counter()  
  10.         {  
  11.             return _counter;  
  12.   
  13.         }  
  14.   
  15.         public void Dispose()  
  16.        {  
  17.            _counter = _counter - 1;   
  18.        }   
  19.     } 
In the service implementation above, we have taken a static counter. To demonstrate Per-Call instance mode:
  • Incrementing a value of a counter in a service constructor. Since the definition of Per-Call Instance mode on each client request service instance will get created. So for each request counter the value will be increased by one in the constructor.
  • When the service is served, the service instance will be disposed of. In the disposed method we are decrementing the counter by one.
  • The Service is returning the counter value.

As you notice we are implanting IDispose to write our own code in the Dispose method. To configure the service in Per-Call Instance mode, the service behavior is configured as InstanceContextMode.PerCall.
 
To test the Per-Call Instance mode configured service, I have created a console application client.

  1. static void Main(string[] args)  
  2. {  
  3.    Service1Client proxy = new Service1Client();  
  4.    var result = proxy.counter();  
  5.    Console.WriteLine(result);  
  6.    Console.ReadKey(true);  
  7.    Service1Client proxy1 = new Service1Client();  
  8.    var result1 = proxy1.counter();  
  9.    Console.WriteLine(result1);  
  10.    Console.ReadKey(true);  

Run the application and you will get the output as:

Run application

As you see we are getting 1 as output on each client request because for each client request the service is creating a new instance and disposing of the instance once the call is served. We are increasing the value of the counter in the constructor and then decreasing it in the dispose method, so across the service call the value of the counter at the service remains the same.

Ideally the value of the counter should increase in each request from the client and you should get output something as in the following:
 
output

We are not getting the output shown above because the service is configured to work in Per-Call Instance Mode. To get the default service as the behavior as in the preceding, remove Instance Mode configured as Per-Call in the service configuration.

Per-Session Instance mode creates a separate Service instance for a separate proxy at the client. So if a Service is configured as a Per-Session or session-full service then for each proxy at the client a new service instance is created. In Per-Session Instance mode there is a client proxy that has a new service instance. In Per-Session Instance mode, WCF maintains a logical session between the client and the service. The Service instance remains in memory throughout the session.

In Per-Session Instance mode, when the client creates a new proxy, either of the same EndPoint or a different EndPoint, the Service creates a new instance to serve the new proxy.

 To configure the service to work in Per-Session mode, there are the following three facets we need to take care of:

  1. Configure behavior of Service to work in Per-Session Instance mode
  2. Create EndPoint using Bindings that support sessions. For example basicHttpBinding may not support Session-full service.
  3. In the contract of the service we need to tell the client that this service will work in session-full mode.

session-full mode 

Let us rewrite the service used in the Per-Call example to use Per-Session Instance Mode.
 
Per-Call example

The Behavior facet of a session-full service is configured by configuring service the Instance mode as InstanceContextMode.PerSession. WCF keeps the Service instance alive for throughout the session. The session terminates when the client closes the proxy. On closing the proxy notifies the service that the session has been closed and the service calls dispose on the service instance.

The contract facet of a session-full service is configured by configuring another attribute of the service behavior SessionMode. SessionMode can be set to either of the following three values:
  1. Allowed
  2. NotAllowed
  3. Required

SessionMode 

By default SessionMode is set to Allowed and it is exposed to the client in Service metadata.

When SessionMode is set to SessionMode.Allowed then transport sessions are allowed but not enforced. The behavior of the service will depend on other two facets, behavior configuration and binding of the service.

Some of the points to keep in mind about allowed SessionMode are as follows:

  • If the Service is configured as PerCall, it will behave as Per Call Instance Mode. Whereas, if the service is configured as PerSession, it will behave as PerSession but if the binding does not support a session, it will behave as a PerCall instance mode.
  • If the service is configured as PerSession and the binding is basicHttpBinding, which is a connection-less binding, then the service cannot use a Transport level session and it will behave as a Per Call configured service.
  • If the binding is WSHttpBinding and the service is configured as a session full service then it will act as a Per-Call instance management service, if security and the reliability of the message is not enabled.

When SessionMode is set to SessionMode.Required then the transport session is enforced. If the service is configured as SessionMode.Required with a service EndPoint in which the binding does not maintain a Transport level session. A run-time error will be encountered at the executing service.

If the service is configured as PerSession and the contract is configured as SessionMode.Required then the service will act as a session-full service. However if binding is not supporting a session then it will throw a run-time error when executing the service. Take an example service configured as PerSession with Contract as SessionMode.Required and binding basicHttpBinding, which is a connectionless binding then service. It cannot use a Transport level session and it will throw an error when the service is loading.

When SessionMode is set to SessionMode.NowAllowed then the transport session is not allowed. Regardless of the service configuration, if the service SessionMode is set to the value NotAllowed then the service will behave as a Per-Call service. We need to be cautious before setting the SessionMode as NotAllowed. For example TCP and IPC protocols maintain a session at the Transport level, so if the End Point is configured as NetTcpBinding or NetNamePipeBinding and the contract as SessionMode.NowAllowed then WCF throws a runtime error when loading the service.

Let us see an InstanceContextMode.PerSession is in action. I have created a service with SessionMode set to the value Required.

  1. [ServiceContract(SessionMode=SessionMode.Required)]  
  2.     public interface IService1  
  3.     {  
  4.         [OperationContract]  
  5.         int counter();       
  6.     }   

Next we implement the service in exactly the same way implemented for InstanceContextMode.PerCall. However this service is configured in InstanceContextMode.PerSession mode.

  1. [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]  
  2.     public class Service1 : IService1  
  3.     {  
  4.         static int _counter = 0;   
  5.         public Service1()  
  6.         {  
  7.             _counter = _counter + 1;   
  8.         }  
  9.        public int counter()  
  10.         {  
  11.             return _counter;   
  12.         }   
  13.         public void Dispose()  
  14.         {  
  15.            _counter = _counter - 1;   
  16.         }   
  17.     } 

In the service implementation above, we have taken a static counter. To demonstrate Per-Session instance mode:

  • Incrementing the value of a counter in the service constructor. As the definition of Per-Session Instance mode for each client proxy, a new service instance will be created. So for each proxy the counter value will be increased by one in the constructor.
  • When the proxy is closed the service instance will be disposed. In the disposed method we are decrementing the counter by one.
  • The Service is returning the counter value.

As you notice we are implanting IDispose to write our own code in Dispose method. To configure the service in Per-Session Instance mode, the service behavior is configured as InstanceContextMode.PerSession.

 To test Per-Session Instance mode configured for the service, I have created a console application client.

  1. Service1Client proxy1 = new Service1Client();  var result = proxy1.counter();  
  2. Console.WriteLine("First Call from Proxy 1 : " + result);  
  3. var result1 = proxy1.counter();  
  4. Console.WriteLine("Second  Call from Proxy 1 : " + result1);              
  5. Service1Client proxy2 = new Service1Client();  
  6. var result2 = proxy2.counter();  
  7. Console.WriteLine("First Call from Proxy2 :" + result2);  
  8. proxy1.Close();  
  9. proxy2.Close();  
  10. Console.ReadKey(true); 

Run the application and you will get output as:

get output

We can infer from the output that for the first proxy the same service instance is being used across the calls. So for both requests the service is returning the same value of the counter. Whereas for the second proxy, the value of the counter has been increased and because a new service instance was created.

The third instance management technique is Single or Singleton Instance Management. When a Service is configured as a Singleton, all clients connect to the same shared Service Instance regardless of EndPoint. In Single Instance management, there is only one instance of the service created and it serves all clients.

In Single Instance mode service Instance created only once. It created when the service host is created and lives forever. It got disposed only when host shuts down. In this instance mode client does not maintain any logical session.

Single instance mode does not restrict the client from consuming a contract with session enabled. Suppose the client is consuming a contract with a session then during the service call the Singleton service instance will have the same Session Id as the client. When the client closes the proxy, that will terminate only the Transport session, not the Singleton service instance. Whereas, if the client is consuming a contract, that does not have a session. That client will also be connected to the same shared singleton service instance.

There are some disadvantages of using Single instance mode. Like it has a scalability problem. All requests to the service will run on a different worker thread, so it will cause a synchronization problem. Only one client could have access to a singleton service instance at a time. It will decrease throughput of the service. Responsiveness is very low. Single instance mode should only be used, when no other options are available. For instance Global Log Book, Single Communication Port and so on.

Let us proceed to and implement Single instance mode. To demonstrate Single instance mode, I have created two service contracts. First the service contract is configured with SessionMode.Required and the second service contract is configured with SessionMode.Allowed.

  1. [ServiceContract(SessionMode=SessionMode.Required)]  
  2.     public interface IService1  
  3.     {  
  4.         [OperationContract]  
  5.         int CounterSessionRequired();           
  6.     }   
  7.   
  8.     [ServiceContract(SessionMode = SessionMode.NotAllowed)]  
  9.     public interface IService2  
  10.     {   
  11.         [OperationContract]  
  12.         int CounterSessionNotAllowed();     
  13.     } 

Next we have implemented the service as below. The same implementation of PerCall or PerSession instance mode is being used here to demonstrate Single instance mode.

  1. [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]  
  2.     public class Service1 : IService1,IService2  
  3.     {  
  4.         static int _counter = 0;   
  5.         public int CounterSessionRequired()  
  6.         {  
  7.             _counter++;  
  8.             return _counter;  
  9.         }  
  10.   
  11.         public int CounterSessionNotAllowed()  
  12.         {  
  13.             _counter++;  
  14.             return _counter;  
  15.         }  
  16.     } 

In the above service implementation, we have taken a static counter to demonstrate Single instance mode. We are increasing the value of the counter in the operation contracts of multiple service contracts. We will expose these two service contracts on various addresses. This can be configured as below:

  1. <services>  
  2.   <service name="MessagePatternDemo.Service1">  
  3.   <!-- Service Endpoints -->  
  4.   <endpoint address="RequiredService"   
  5.       binding="wsHttpBinding"   
  6.       contract="MessagePatternDemo.IService1">  
  7.   </endpoint>  
  8.   <endpoint address="AllowedService"  
  9.       binding="wsHttpBinding"   
  10.       contract="MessagePatternDemo.IService2">   
  11.   </endpoint>   
  12.      <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>  
  13.   </service>  
  14. </services> 

Now at the client side both services are consumed as below:

  1. Service1Client proxy1 = new Service1Client();  
  2. var result = proxy1.CounterSessionRequired();  
  3. Console.WriteLine("First Call from Proxy 1 : " + result);                          
  4. Service2Client proxy2 = new Service2Client();  
  5. var result2 = proxy2.CounterSessionNotAllowed();  
  6. Console.WriteLine("First Call from Proxy2 :" + result2);  
  7. proxy1.Close();  
  8. proxy2.Close();  
  9. Console.ReadKey(true); 

We are calling both services with  different proxy but at the service side a single service instance is being created. As an output each time you will get an increased value of the counter from the service. So we can conclude that a single instance of the service is being used by all proxies at the clients.

In this article, we learned about Instance Modes on WCF Services. There are three types and we need to choose them wisely on the basis of requirements. When choosing an instance mode ensure that you have configured the service with proper binding. For example don't make the mistake of creating a Session-full service with basicHttpBinding. I hope this article is useful to you. Thanks for reading.