Click here to Skip to main content
15,886,799 members
Articles / WCF

Understanding Instance Management in WCF

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
9 Jan 2015CPOL4 min read 7.9K   2  
Understanding instance management in WCF

Instance management is the technique WCF uses to bind client requests to service instances, governing which service instance handles which client request, and when. WCF supports 3 types of instance activation.

  • Per Call: per call services allocate and destroy a new service instance for each client request
  • Per Session: session full services allocate a service instance for each client connection
  • Singleton: singleton services share the same service instance for all clients, across all connections and activations

By and large, the service instance mode is strictly a server side implementation detail, that should not manifest itself on the client side in any way.

Now let’s define a service that demonstrates the instance management in real life.

Creating the Class Library

Let’s create a service, create a new project, take a Class Library template, name it InstanceLib, let’s do some house keeping with the newly created project.

  • Delete the file Class1.cs from the project workspace.
  • Add a new Interface named ISingleCallService to the project, a new file ISingleCallService.cs will be added to the project.
  • Add a new Class named SingleCallService, to the project. That will implement the ISingleCallService interface, a new file SingleCallService.cs will be added to the project.
  • Add a new Interface named ISessionService to the project, a new file ISessionService.cs will be added to the project.
  • Add a new Class named SessionService, to the project. that will implement the ISessionService interface, a new file SessionService.cs will be added to the project. <!--EndFragment-->
  • Add a new Interface named ISingletonService to the project, a new file ISingletonService.cs will be added to the project.
  • Add a new Class named SingletonService, to the project. that will implement the ISingletonService interface, a new file SingletonService.cs will be added to the project.

To keep things simple, let’s assume that each interface defines only one method, which simply adds a passed value to its member variable.

Defining Interfaces

So let’s define interface for each service.

C#
// Listing of ISingleCallService.cs

using System;
using System.Text;
using System.ServiceModel;

namespace InstanceLib
{
    [ServiceContract]
    interface ISingleCallService
    {
        [OperationContract]
        double AddValue (double dblNum);
    }
} 

// Listing of ISessionService.cs

using System;
using System.Text;
using System.ServiceModel;

namespace InstanceLib
{
    [ServiceContract]
    interface ISessionService
    {
        [OperationContract]
        double AddValue (double dblNum);
    }
}

// Listing of ISingletonService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace InstanceLib
{
    [ServiceContract]
    interface ISingletonService
    {
        [OperationContract]
        double AddValue (double dblNum);
    }
}
  • <!--EndFragment--><!--EndFragment-->

Implementing Interfaces

Let’s implement each interface, as shown below:

C#
// Listing of SingleCallService.cs

using System;
using System.Text;
using System.ServiceModel ;

namespace InstanceLib
{
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]  
    public class SingleCallService : ISingleCallService
    {
        private double m_dblTotal = 0 ;

        public double AddValue(double dblVal)
        {
            m_dblTotal += dblVal;
            return m_dblTotal;
        }
    }
}
Important

You can notice ServiceBehavior attribute of the class, which has been defined as InstanceContextMode.PerCall, it specifies that a new InstanceContext object is created prior to and recycled subsequent to each call. If you omit this attribute or do not specify, then InstanceContextMode.PerCall is assumed by default.

C#
// Listing of SessionService.cs

using System;
using System.Text;
using System.ServiceModel;

namespace InstanceLib
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class SessionService : ISessionService
    {
        private double m_dblTotal = 0 ;

        public double AddValue(double dblVal)
        {
            m_dblTotal += dblVal;
            return m_dblTotal;
        }
    }
}
Important

You can notice ServiceBehavior attribute of the class, which has been defined as InstanceContextMode.PerSession, it specifies that InstanceContext object is created for each session.

C#
// Listing of SingletonService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace InstanceLib
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class SingletonService : ISingletonService
    {
        private double m_dblTotal = 0 ;

        public double AddValue(double dblVal)
        {
            m_dblTotal += dblVal;
            return m_dblTotal;
        }
    }
}
Important

You can notice ServiceBehavior attribute of the class, which has been defined as InstanceContextMode.Singlel, it specifies that only one InstanceContext object is used for all incoming calls and is not recycled to the calls. If the service object does not exist, one is created.

If you notice the all 3 service implementation, you will notice the difference in ServiceBehavior class attribute of each class, apart from that, all interfaces that have been implemented have the same implementation. They simply add a passed value to a member variable of the class.

Build the project and your Class Library is ready.

Hosting the Service

For the sake of simplicity, I have hosted this service as a self hosted service, to create the Host application, create a new Console based application.

Before we write any code for the Host application, let’s define the configuration file for the Service(s).

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>

      <!–************************ Single Call Service ************************ >
      <service name="InstanceLib.SingleCallService" 
      behaviorConfiguration="SingleCallServiceBehavior"> 
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9011/SingleCallService"/>
            <add baseAddress="net.tcp://localhost:9012/SingleCallService"/>
          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9011/SingleCallService" 
        binding="wsHttpBinding" contract="InstanceLib.ISingleCallService"/>
        <endpoint address="net.tcp://localhost:9012/SingleCallService" 
        binding="netTcpBinding" contract="InstanceLib.ISingleCallService"/>
        <endpoint address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" 
        contract="IMetadataExchange"/>
      </service>

      <!—************************ Single Session Service ************************–>
      <service name="InstanceLib.SessionService" 
     behaviorConfiguration="SessionServiceBehavior"> 
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9013/SessionService"/>
            <add baseAddress="net.tcp://localhost:9014/SessionService"/>
          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9013/SessionService" 
        binding="wsHttpBinding" contract="InstanceLib.ISessionService"/>
        <endpoint address="net.tcp://localhost:9014/SessionService" 
        binding="netTcpBinding" contract="InstanceLib.ISessionService"/>
        <endpoint address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" 
        contract="IMetadataExchange"/>
      </service>

      <!—************************** Singleton Service **************************–>
      <service name="InstanceLib.SingletonService" 
     behaviorConfiguration="SingletonServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9015/SingletonService"/>
            <add baseAddress="net.tcp://localhost:9016/SingletonService"/>
          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9015/SingletonService" 
        binding="wsHttpBinding" contract="InstanceLib.ISingletonService"/>
        <endpoint address="net.tcp://localhost:9016/SingletonService" 
        binding="netTcpBinding" contract="InstanceLib.ISingletonService"/>
        <endpoint address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" 
        contract="IMetadataExchange"/>
      </service>

    </services>

    <!– **************************** behaviors ************************** >
    <behaviors>
      <serviceBehaviors>

        <!– Single Call Service Behavior >
        <behavior name="SingleCallServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>

        <!–Single Session Service Behavior >
        <behavior name="SessionServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>

        <!–Singleton Service Behavior >
        <behavior name="SingletonServiceBehavior">

          <serviceMetadata httpGetEnabled="true"/>
        </behavior>

      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>
</configuration>

Now let’s analyze the Configuration file.

Single Call Service

XML
<!–******************* Single Call Service ************************** >
      <service name="InstanceLib.SingleCallService" 
      behaviorConfiguration="SingleCallServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9011/SingleCallService"/>
            <add baseAddress="net.tcp://localhost:9012/SingleCallService"/> 
          </baseAddresses> 
        </host>

        <endpoint address="http://localhost:9011/SingleCallService" 
        binding="wsHttpBinding" contract="InstanceLib.ISingleCallService"/>
        <endpoint address="net.tcp://localhost:9012/SingleCallService" 
        binding="netTcpBinding" contract="InstanceLib.ISingleCallService"/>
        <endpoint address="mex" 
        binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" 
        binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

Session Service

<!—************************* Single Session Service ************************* –>
      <service name="InstanceLib.SessionService" 
      behaviorConfiguration="SessionServiceBehavior">
        <host>
          <baseAddresses> 
            <add baseAddress="http://localhost:9013/SessionService"/>
            <add baseAddress="net.tcp://localhost:9014/SessionService"/>
          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9013/SessionService" 
        binding="wsHttpBinding" contract="InstanceLib.ISessionService"/>
        <endpoint address="net.tcp://localhost:9014/SessionService" 
        binding="netTcpBinding" contract="InstanceLib.ISessionService"/>
        <endpoint address="mex" 
        binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" 
        binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

Singleton Service

<!—************************** Singleton Service **************************–> 
      <service name="InstanceLib.SingletonService" 
     behaviorConfiguration="SingletonServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9015/SingletonService"/>
            <add baseAddress="net.tcp://localhost:9016/SingletonService"/>
          </baseAddresses> 
        </host>

        <endpoint address="http://localhost:9015/SingletonService" 
        binding="wsHttpBinding" contract="InstanceLib.ISingletonService"/>
        <endpoint address="net.tcp://localhost:9016/SingletonService" 
        binding="netTcpBinding" contract="InstanceLib.ISingletonService"/>
        <endpoint address="mex" 
        binding="mexHttpBinding" 
        contract="IMetadataExchange"/>
        <endpoint address="mex" 
        binding="mexTcpBinding" 
        contract="IMetadataExchange"/>
      </service>

Writing Code to Host the Service

C#
// Listing of Program.cs

using System;
using System.Text;
using System.ServiceModel;

namespace InstanceLibHost
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost m_SingleCallHost = null;
            ServiceHost m_SingleSessHost = null;
            ServiceHost m_SingletonHost = null;

            Console.WriteLine("\nHosting Single Call Service at >> " );
            Console.WriteLine("    http://localhost:9011/SingleCallService");
Console.WriteLine("    net.tcp://localhost:9012/SingleCallService");
       
            try
            {
                m_SingleCallHost = new ServiceHost(typeof(InstanceLib.SingleCallService));
                m_SingleCallHost.Open();
            }
            catch (Exception eX)
            {
                Console.WriteLine("Failed while starting 
                Single Call Service Service [" + eX.Message + "]");
                m_SingleCallHost = null;
            }

            if ( m_SingleCallHost!= null ) 
            Console.WriteLine("Single Call Service hosted successfully . . .");

            Console.WriteLine("\nHosting Single Session Service at >> ");
            Console.WriteLine("    http://localhost:9013/SessionService");
Console.WriteLine("    net.tcp://localhost:9014/SessionService");
            try
            {
                m_SingleSessHost = new ServiceHost(typeof(InstanceLib.SessionService));
                m_SingleSessHost.Open();
            }
            catch (Exception eX)
            {
                Console.WriteLine("Failed while starting Single 
                Session Service [" + eX.Message + "]");
                m_SingleSessHost = null;
            }

            if (m_SingleSessHost != null) Console.WriteLine
            ("Single Session Service hosted successfully . . .");

            Console.WriteLine("\nHosting Singlton Service at >> " );
            Console.WriteLine("    http://localhost:9015/SingletonService" );
            Console.WriteLine("    net.tcp://localhost:9016/SingletonService");
       
            try
            {
                m_SingletonHost = new ServiceHost(new InstanceLib.SingletonService());
                m_SingletonHost.Open();
            }
            catch (Exception eX)
            {
                Console.WriteLine("Failed while starting Service [" + eX.Message + "]");
                m_SingletonHost = null;
            }
            if (m_SingletonHost != null) Console.WriteLine("Singleton Service hosted successfully . . .");

            Console.WriteLine("Press any key to close . . ." );
            Console.ReadKey();

            m_SingleCallHost.Close ();
            m_SingleSessHost.Close ();
            m_SingletonHost.Close () ;

            m_SingleCallHost = null;
            m_SingleSessHost = null;
            m_SingletonHost = null;
        }
    }
}

Build and Execute the Service

Open a command prompt and execute the host. Here is the output.

image

Now when the service is hosted and running, let’s now create a client, which is actually going to use this service.

Creating Client

Creating the Base Project

Take a console based application.

Generating Proxies

While the host application is running, right click on the client application project, click on:

Generate Proxy for SingleCallService.

References –> Add Service Reference

In the address bar, type the address of the mex endpoint address of SingleCallService as shown below.

image

In the namespace, type some good name, let’s say SingleCallServiceReference for instance.

Hit OK, this will simply add a new file app.config to the project. and a new item in the Service Reference node of the project.

Generate Proxy for SessionService.

References –> Add Service Reference

In the address bar, type the address of the mex endpoint address of SessionService as shown below.

image

In the namespace, type some good name, let’s say SessionServiceReference for instance.

Generate Proxy for SingletonService.

References –> Add Service Reference

In the address bar, type the address of the mex endpoint address of SingletonService as shown below.

image

In the namespace, type some good name, let’s say SingletonServiceReference for instance.

Now when you have added references of all 3 services, let’s write code for the client to use these services.

C#
// Listing of Program.cs

using System;
using System.Text;

namespace InstanceClient
{
class Program
    {
        static void Main(string[] args)
        {
            SingleCallServiceReference.SingleCallServiceClient objSvc1 = 
            new SingleCallServiceReference.SingleCallServiceClient("WSHttpBinding_ISingleCallService");
            SingleCallServiceReference.SingleCallServiceClient objSvc2 = 
            new SingleCallServiceReference.SingleCallServiceClient("NetTcpBinding_ISingleCallService");

Console.WriteLine("Client 1 Calling Single Call Service 3 times Using Http Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue1 = 10;
                double dblResult1 = objSvc1.AddValue(dblValue1);
                Console.WriteLine("Using HTTP Binding >> 
                Input Value : {0:F2} Return value : {1:F2}", dblValue1, dblResult1);
            }

Console.WriteLine("Client 2 Calling Single Call Service 3 times using TCP Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue2 = 10;
                double dblResult2 = objSvc2.AddValue(dblValue2);
                Console.WriteLine("Using TCP  Binding >> 
                Input Value : {0:F2} Return value : {1:F2}", dblValue2, dblResult2);
            }

SessionServiceReference.SessionServiceClient objSvc3 = 
new SessionServiceReference.SessionServiceClient("WSHttpBinding_ISessionService");
            SessionServiceReference.SessionServiceClient objSvc4 = 
            new SessionServiceReference.SessionServiceClient("NetTcpBinding_ISessionService");

Console.WriteLine("\n\nClient 1 Calling Single Session Service 3 times Using Http Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue1 = 10;
                double dblResult1 = objSvc3.AddValue(dblValue1);
                Console.WriteLine("Using HTTP Binding >> 
                Input Value : {0:F2} Return value : {1:F2}", dblValue1, dblResult1);
            }

Console.WriteLine("Client 2 Calling Single Session Service 3 times using TCP Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue2 = 10;
                double dblResult2 = objSvc4.AddValue(dblValue2);
                Console.WriteLine("Using TCP  Binding >> 
                Input Value : {0:F2} Return value : {1:F2}", dblValue2, dblResult2);
            }

SingletonServiceReference.SingletonServiceClient objSvc5 = 
new SingletonServiceReference.SingletonServiceClient("WSHttpBinding_ISingletonService");
            SingletonServiceReference.SingletonServiceClient objSvc6 = 
            new SingletonServiceReference.SingletonServiceClient("NetTcpBinding_ISingletonService");

Console.WriteLine("\n\nClient 1 Calling Singleton Service 3 times Using Http Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue1 = 10;
                double dblResult1 = objSvc5.AddValue(dblValue1);
                Console.WriteLine("Using HTTP Binding >> 
                Input Value : {0:F2} Return value : {1:F2}", dblValue1, dblResult1);
            }

Console.WriteLine("Client 2 Calling Singleton Service 3 times using TCP Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue2 = 10;
                double dblResult2 = objSvc6.AddValue(dblValue2);
                Console.WriteLine("Using TCP  Binding >> 
                Input Value : {0:F2} Return value : {1:F2}", dblValue2, dblResult2);
            }

Console.WriteLine("Press any key to close . . . ");
            Console.ReadKey();
        }
    }
}

Open command prompt and execute the client to see the output.

image

Open one more command prompt, and execute another instance of client.

image

As you can see from the output, all the instance mode in action.

Image 7 Image 8

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India
More than 10 years of experience in designing and development of GUIs and Middleware for industrial control systems.

Comments and Discussions

 
-- There are no messages in this forum --