Managing State and Service Instances in a WCF service – The case of a ShoppingCart : Part 2

This post will continue our discussion about managing state and service instances in a WCF service. In a previous post we created a WCF service holding a shoppingCart list private instance variable, where clients consuming that service could store their items. If you haven’t already read that post, for the love of God go ahead and read it first. We saw that if a client consume the operation “AddItemToCart” with the same ProductNumber that causes the variable volume of that item to be increased by one. Absolute normal. Well, some questions may popped up in your mind. What if another client call the same operation with the same product number? Is he going to order 1 or 3 items of that kind? Which service instance will actually serve him? The one that have been created when the service was consumed for the first time by the first client or a new instance created when the 2nd client consumed the service? Why don’t we see it in action.

Go to ShoppingCart solution’s folder, copy and paste the client’s folder “ShoppingCartClient” with new name “ShoppingCartNewClient”. After that, go inside that folder and also change the name of the project file to ShoppingCartNewClient. Import that new project to your solution by right clicking the solution and selecting “Add existing project..”. Navigate to the new folder and add the new project. This will be our new client project. Your solution should look like this now.

shoppingSolution

Right click the solution and Set ShoppingCartHost, ShoppingCartClient, ShoppingCartNewClient as Start projects. Before running them, in order to know which client is who, add in the two clients projects Program.cs file, some code that displays that information.

//Other code omitted
string cartContents = proxy.GetShoppingCart();
Console.WriteLine("First/Second client starting..");
Console.WriteLine(cartContents);
//Other code omitted

Build and Start without debugging. Press enter in both client projects. What do you see?

twodifinst

What you see is what you get. Two different service instances serving two different clients. That tell us that when a client consumes a service for the first time, by default an instance of the service is itself created by the host, hence a new ShoppingCart list which is private instance variable. This instance is only destroyed after the client closes the connection which means that it can hang around between calls (from same client). If another client application calls the WCF service, by default a new Service instance will be created and will maintain a new shoppingCart list for serving that client. Things starting to getting clearer I hope. Let’s dive in a little more. What if a client consumes the service, closes the connection and then re-consumes the service? Is he going to use the same old instance? Is he going to use the same shoppingCart list from the first request? Go and add some code to the first client Program.cs to test it.

sing System.ServiceModel;
using ShoppingCartClient.ShoppingCartService;

namespace ShoppingCartClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Press ENTER when the service has started");
            Console.ReadLine();
            try
            {
                // Connect to the ShoppingCartService service
                ShoppingCartServiceClient proxy = new ShoppingCartServiceClient("WS2007HttpBinding_IShoppingCartService");
                // Add two water bottles to the shopping cart
                proxy.AddItemToCart("SA-M687");
                proxy.AddItemToCart("SA-M687");
                // Add a mountain seat assembly to the shopping cart
                proxy.AddItemToCart("SA-M198");
                // Query the shopping cart and display the result
                string cartContents = proxy.GetShoppingCart();
                Console.WriteLine("First client starting..");
                Console.WriteLine(cartContents);
                Console.WriteLine();
                // Disconnect from the ShoppingCartService service
                proxy.Close();

                //Second call
                ShoppingCartServiceClient newProxy = new ShoppingCartServiceClient("WS2007HttpBinding_IShoppingCartService");
                Console.WriteLine("Same client consumes for second time");
                newProxy.AddItemToCart("SA-M687");
                newProxy.AddItemToCart("SA-M687");
                // Add a mountain seat assembly to the shopping cart
                newProxy.AddItemToCart("SA-M198");
                // Query the shopping cart and display the result
                string newCartContents = newProxy.GetShoppingCart();
                Console.WriteLine("First client starting..");
                Console.WriteLine(newCartContents);
                // Disconnect from the ShoppingCartService service
                newProxy.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
            }
            Console.WriteLine("Press ENTER to finish");
            Console.ReadLine();
        }
    }
}

If you Start without debugging you will see that the same client used two different instances of the service.

clientconsumestwotimes

It’s time to be more specific now. The WCF service instance which is created to handle requests from a specific client application and maintain state information between requests from that client, is called “Session”. When the client uses a proxy object to consume the service, the WCF runtime creates a Session to hold a service instance and any state data required by that instance. The Session is terminated when the client application decides to close the proxy object. A WCF service has an attribute called ServiceBehavior which has an “InstanceContextMode” property. This property actually allows you to control the relationship between client applications and instances of a service. The default value is “PerSession” for which we don’t need to tell more, since we saw how it functions in action.

namespace ShoppingCartService
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class ShoppingCartServiceImpl : IShoppingCartService
    {
        private List shoppingCart = new List();
        //other code omitted
    }
}

The “InstanceContextMode” property can take the value “PerCall”. This instance context mode, creates a new instance of the service every time the client application invokes an operation. The instance is destroyed when the operation completes. This is good for scenarios where thousands of clients consumes the service. You definitely don’t want to create a service instance for each client, since the amount of memory required would be forbidden. But how is the state maintained in this case? Let’s leave that for another post. Go ahead, change the above code in the service implementation class, modifying the InstanceContextMode to “PerCall” and run the solution.

percall

Why zero? Were those items for free? Yeah right.. What actually happened is that each time a service operation such as “AddItemToCart” completes, the shoppingCart list is destroyed. When time comes for the “GetShoppingCart” operation, trying to iterate in the shoppingCart items, finds out that it’s just empty.

emptyshop
The last alternative value for the InstanceContextMode property is the value “Single”. Easy to understand it’s functionality. A service instance is created when the service is consumed for the very first time from a client. Each other client who tries to consume that service, will use the same service instance. So when does that instance is destroyed? The answer is when the host application shut the service down. Go and try the service behavior with the “Single” value. Run without debugging, press enter for the first client and then for the new.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class ShoppingCartServiceImpl : IShoppingCartService

singleinstance

I hope the new client has enough money in his pockets. Both clients used the same service instance every time they consumed the service, hence the same shoppingCart list variable. I hope you have understood till now, how WCF runtime can manage service instances. I am also sure that other things may popped up in your mind again, like how could someone maintain the state of the instance, for example the shoppingCart list, when using the “PerCall” approach? Well, that’s what we are going to see in a next post.



Categories: WCF

Tags:

1 reply

Trackbacks

  1. Managing State and Service Instances in a WCF service : Part 3 – Maintaining State with the PerCall Instance Context Mode | chsakell's Blog

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 )

Connecting to %s

%d bloggers like this: