in the process of creating a WCF service I ran into a term that\'s new to me. Basically when specifying the InstanceContextMode
I have a few options, including;
Yes, sharing the service instance means that there's only one instance created by the server, shared between requests.
In particular, the constructor of the service object will be called once, when the instance is created. This can be important for example if you use some form of authentication with impersonating the context's identity (shared instances could potentially require some extra work to handle such case).
InstanceContextMode.Single
corresponds to a singleton service i.e. the service instance server side is the same for all the incoming requests.
A few comments:
It means that only one instance of your class is created by WCF. All requests are handled by that instance. Multithreading and concurrency issues included.
Although it would probably be an implementation detail, I doubt your class is persistet (it would have to be serializable for that, which is not a requirement). The one instance simply exists as long as it is needed (i.e. the associated ServiceHost
is open).
Per the docs:
Only one InstanceContext object is used for all incoming calls and is not recycled subsequent to the calls. If a service object does not exist, one is created.
So there is only one instance, and it's not cleaned up after a call is made. This is like a Singleton for your WCF service. So you need to be careful about shared memory and resources.
To answer your question - yes, this is the way it works.
UPDATE Added sample:
I modified a few samples from MSDN to show the effects of InstanceContextMode.Single
. You'll see the operation count will continue to increment even though I use two different clients. If I change the InstanceContextMode
to PerCall
, the count will be different (it will be zero).
self-hosted service:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class CalculatorService : ICalculatorInstance
{
static Object syncObject = new object();
static int instanceCount;
int instanceId;
int operationCount;
public CalculatorService()
{
lock (syncObject)
{
instanceCount++;
instanceId = instanceCount;
}
}
public double Add(double n1, double n2)
{
operationCount++;
return n1 + n2;
}
public double Subtract(double n1, double n2)
{
Interlocked.Increment(ref operationCount);
return n1 - n2;
}
public double Multiply(double n1, double n2)
{
Interlocked.Increment(ref operationCount);
return n1 * n2;
}
public double Divide(double n1, double n2)
{
Interlocked.Increment(ref operationCount);
return n1 / n2;
}
public string GetInstanceContextMode()
{ // Return the InstanceContextMode of the service
ServiceHost host = (ServiceHost)OperationContext.Current.Host;
ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
return behavior.InstanceContextMode.ToString();
}
public int GetInstanceId()
{ // Return the id for this instance
return instanceId;
}
public int GetOperationCount()
{ // Return the number of ICalculator operations performed
// on this instance
lock (syncObject)
{
return operationCount;
}
}
}
public class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:12345/calc");
using (ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddress))
{
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since
// no endpoints are explicitly configured, the runtime will create
// one endpoint per base address for each service contract implemented
// by the service.
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
// Close the ServiceHost.
host.Close();
}
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
}
}
client:
class Program
{
static void Main()
{
// Create a client.
CalculatorInstanceClient client = new CalculatorInstanceClient();
string instanceMode = client.GetInstanceContextMode();
Console.WriteLine("InstanceContextMode: {0}", instanceMode);
Console.WriteLine("client1's turn");
Console.WriteLine("2 + 2 = {0}", client.Add(2, 2).ToString());
Console.WriteLine("3 - 1 = {0}", client.Subtract(3, 1).ToString());
Console.WriteLine("number of operations = {0}", client.GetOperationCount().ToString());
// Create a second client.
CalculatorInstanceClient client2 = new CalculatorInstanceClient();
Console.WriteLine("client2's turn");
Console.WriteLine("2 + 2 = {0}", client2.Add(2, 2).ToString());
Console.WriteLine("3 - 1 = {0}", client2.Subtract(3, 1).ToString());
Console.WriteLine("number of operations = {0}", client2.GetOperationCount().ToString());
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
}
}