Preface
The main content of this record is as follows: Session, instantiation, and concurrency.
Part 1 -- Session
A session is a relationship between all messages sent between two endpoints.
Set the System. ServiceModel. ServiceContractAttribute. SessionMode value in the service agreement.
-- Allowed: by default, the client can connect and choose to establish a session or not to establish a session.
-- All Required calls (that is, basic message exchange that supports calls) must be part of the same conversation.
-- NotAllowed: Disable a session
A WCF session has the following conceptual features:
-- They are explicitly started and terminated by calling the application.
-- Messages transmitted during a session are processed in the order of received messages.
-- A session associates a group of messages to form a session. The meaning of this association is abstract. For example, a session-based channel may associate messages based on the shared tags in the message body. The function that can be derived from a session depends on the nature of the association.
-- There is no common data storage area associated with the WCF session.
Differences between ASP. NET sessions and WCF sessions
-- ASP. NET sessions are always started by the server.
-- ASP. NET sessions were originally unordered.
-- ASP. NET sessions provide a common cross-request data storage mechanism.
Client Applications and service applications interact with sessions in different ways.
-- The client application starts the session and receives and processes the messages sent in the session.
-- Service applications can use sessions as extension points to add other behaviors. This can be done by directly using InstanceContext or implementing a custom instance context provider.
When the WCF Service accepts client sessions, the following features are enabled by default:
-- Use the same user-defined service object to process all calls between WCF client objects.
-- In addition to this instantiation behavior, different session-based bindings also provide other functions.
Session type provided by the system
-- System. ServiceModel. ChannelsSecurityBindingElement supports secure-based sessions. The two communication ends use a unified security conversation.
-- System. ServiceModel. WSHttpBinding binding (including support for secure sessions and reliable sessions) by default, only secure sessions encrypted and digitally signed are used.
-- System. ServiceModel. NetTcpBinding supports TCP/IP-based sessions to ensure that all messages are associated by socket-level connections.
-- The System. ServiceModel. Channels. ReliableSessionBindingElement element implements the WS-ReliableMessaging specification and provides support for reliable sessions. In a reliable session, you can configure the message to be transmitted in sequence and only once, so that the message can be kept confidential even if it passes through multiple nodes during the conversation.
Part 2-session instance
First, let's look at the service interface.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)] public interface ICalculatorSession { [OperationContract(IsOneWay=true)] void Clear(); [OperationContract(IsOneWay = true)] void AddTo(double n); [OperationContract(IsOneWay = true)] void SubtractFrom(double n); [OperationContract(IsOneWay = true)] void MultiplyBy(double n); [OperationContract(IsOneWay = true)] void DivideBy(double n); [OperationContract] double Result(); }
The session configuration model here is Required.
Next, let's take a look at the service implementation.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class CalculatorService : ICalculatorSession { double result = 0.0D; public void Clear() { result = 0.0D; } public void AddTo(double n) { result += n; } public void SubtractFrom(double n) { result -= n; } public void MultiplyBy(double n) { result *= n; } public void DivideBy(double n) { result /= n; } public double Result() { return result; } }
InstanceContextMode can be used to process the number of service instances that are called in the incoming message.
// Abstract: // create a new System. ServiceModel. InstanceContext object for each session. PerSession = 0, // Summary: // The new System. ServiceModel. InstanceContext object is created before each call and recycled after each call. If no session is created for the channel, the behavior of this value is the same as/System. ServiceModel. InstanceContextMode. PerCall. PerCall = 1, // Summary: // only one System. ServiceModel. InstanceContext object is used for all incoming calls and is not recycled after the call. If the service object does not exist, create one. Single = 2,
In this case, I use iisto carry the service, and then use svcutil.exe to generate the client proxy class and configuration file.
Next let's take a look at how the client calls
CalculatorSessionClient client = new CalculatorSessionClient(); client.Clear(); client.AddTo(100.0D); client.SubtractFrom(50.0D); client.MultiplyBy(17.65D); client.DivideBy(2.0D); double result = client.Result(); Console.WriteLine("(((0 + 100) - 50) * 17.65) / 2 = {0}", result); //Closing the client gracefully closes the connection and cleans up resources client.Close(); Console.WriteLine(); Console.WriteLine("Press <ENTER> to terminate client."); Console.ReadLine(); }
Because we set the service implementation class to [ServiceBehavior (InstanceContextMode = InstanceContextMode. Single)]
If it is set to [ServiceBehavior (InstanceContextMode = InstanceContextMode. PerCall)], the result is as follows: a service instance is created every time a method is called.
This is a sample session code example of a session.
Part 2 -- instantiation
Instantiation (using the System. ServiceModel. ServiceBehaviorAttribute. InstanceContextModel attribute to set) controls how to create an InstanceContext to respond to incoming messages.
By default, each InstanceContext is associated with a user-defined service object. Therefore, you can set the InstanceContextMode attribute to control the instantiation of user-defined service objects.
The following instantiation modes can be used:
PerCall: Creates a new InstanceContext (and corresponding service objects) for each client request ).
Perseesion: Creates a new InstanceContext (and corresponding service objects) for each new client session ), and maintain the session during the lifetime of the session (this requires binding to support sessions ).
Single: A Single InstanceContext (and corresponding service objects) processes all client requests within the lifetime of an application.
Part 2 -- instantiate an instance
First, let's look at the service contract for addition, subtraction, multiplication, and division.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)] public interface ICalculator { [OperationContract] double Add(double n1, double n2); [OperationContract] double Subtract(double n1, double n2); [OperationContract] double Multiply(double n1, double n2); [OperationContract] double Divide(double n1, double n2); }
The following are three service contracts that obtain service settings and inherit from the preceding service contracts for addition, subtraction, multiplication, and division.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)] public interface ICalculatorInstance : ICalculator { [OperationContract] string GetInstanceContextMode(); [OperationContract] int GetInstanceId(); [OperationContract] int GetOperationCount(); }
Next, let's look at the service implementation.
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; } }
We can find that there is a constructor in the Service implementation. This constructor is used to check the number of service instances.
In service implementation, GetInstanceContextMode is used to obtain the instance mode of the current service.
GetOperationCount is used to return the number of Operation times in the service.
At the end, you can use iisto carry the wcfservice and svcutil.exe to get the client proxy class and client file configuration of the current service.
The above code shows InstanceContextMode = InstanceContextMode. Single
Then let's take a look at the client call code.
Static void Main () {// Create a client // first instantiate a Service proxy class CalculatorInstanceClient client = new CalculatorInstanceClient (); /// call GetInstanceContextMode on the server side to obtain the service mode string instanceMode = client. getInstanceContextMode (); Console. writeLine ("InstanceContextMode: {0}", instanceMode); // call the operation calculation DoCalculations (client ); // Create a second client // then instantiate a client proxy class CalculatorInstanceClient client2 = new CalculatorInstanceClient (); // call DoCalculations (client2) for the second operation calculation ); // Closing the client gracefully closes the connection and cleans up resources client. close (); Console. writeLine (); Console. writeLine ("Press <ENTER> to terminate client. "); Console. readLine ();} static void DoCalculations (CalculatorInstanceClient client) {// Call the Add service operation. double value1 = 100.00D; double value2 = 15.99D; double result = client. add (value1, value2); Console. writeLine ("Add ({0}, {1}) = {2}", value1, value2, result); Console. write ("InstanceId: {0}", client. getInstanceId (); Console. writeLine (", OperationCount: {0}", client. getOperationCount (); // Call the Subtract service operation. value1 = 145.00D; value2 = 76.54D; result = client. subtract (value1, value2); Console. writeLine ("Subtract ({0}, {1}) = {2}", value1, value2, result); Console. write ("InstanceId: {0}", client. getInstanceId (); Console. writeLine (", OperationCount: {0}", client. getOperationCount (); // Call the Multiply service operation. value1 = 9.00D; value2 = 81.25D; result = client. multiply (value1, value2); Console. writeLine ("Multiply ({0}, {1}) = {2}", value1, value2, result); Console. write ("InstanceId: {0}", client. getInstanceId (); Console. writeLine (", OperationCount: {0}", client. getOperationCount (); // Call the Divide service operation. value1 = 22.00D; value2 = 7.00D; result = client. divide (value1, value2); Console. writeLine ("Divide ({0}, {1}) = {2}", value1, value2, result); Console. write ("InstanceId: {0}", client. getInstanceId (); Console. writeLine (", OperationCount: {0}", client. getOperationCount ());}
The execution result is as follows:
The service mode is Single.
InstanceId is always 1, indicating the role of Single
OperationCount is incremental to 88 call results of course 8.
Instantiate code instance
You can change it to another two modes to test the effect.
Part 3 -- concurrency
Concurrency controls the number of threads in the active State at any time in the InstanceContext.
This control is implemented by combining System. ServiceModel. ServiceBehaviorAttribute. ConcurrencyModel and ConcurrencyMode enumeration.
There are three available concurrency modes:
Single: allows each context colleague to use a thread to process messages in the context of the instance. Other threads wishing to use the same instance context must be blocked until the original thread exits the instance context.
Multiple: each service instance can have Multiple threads that process messages simultaneously. To use this concurrency mode, the service implementation must be thread-safe.
Reentrant: each service instance can process only one message at a time, but can accept Reentrant operation calls. These calls are accepted only when the service is provided through the WCF client object.
The usage of concurrency is related to the instantiation mode. In the PerCall instantiation process, there is no relationship with concurrency, because each message is processed by a new InstanceContext, so there will never be more than one active thread in InstanceContext.
Part 3-concurrent instances
First, let's take a look at the definition of the service contract.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")] public interface ICalculator { [OperationContract] double Add(double n1, double n2); [OperationContract] double Subtract(double n1, double n2); [OperationContract] double Multiply(double n1, double n2); [OperationContract] double Divide(double n1, double n2); } // Define a service contract to inspect concurrency state [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")] public interface ICalculatorConcurrency : ICalculator { [OperationContract] string GetConcurrencyMode(); [OperationContract] int GetOperationCount(); }
Second, let's take a look at the service implementation.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single)] // Uses Thread.Sleep to vary the execution time of each operation public class CalculatorService : ICalculatorConcurrency { int operationCount; public double Add(double n1, double n2) { operationCount++; System.Threading.Thread.Sleep(180); return n1 + n2; } public double Subtract(double n1, double n2) { operationCount++; System.Threading.Thread.Sleep(100); return n1 - n2; } public double Multiply(double n1, double n2) { operationCount++; System.Threading.Thread.Sleep(150); return n1 * n2; } public double Divide(double n1, double n2) { operationCount++; System.Threading.Thread.Sleep(120); return n1 / n2; } public string GetConcurrencyMode() { // Return the ConcurrencyMode of the service ServiceHost host = (ServiceHost)OperationContext.Current.Host; ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>(); return behavior.ConcurrencyMode.ToString(); } public int GetOperationCount() { // Return number of operations return operationCount; } }
Third client call
static void Main() { // Create a client CalculatorConcurrencyClient client = new CalculatorConcurrencyClient(); Console.WriteLine("Press <ENTER> to terminate client once the output is displayed."); Console.WriteLine(); // Communicate with service using asynchronous methods. client.BeginGetConcurrencyMode(GetConcurrencyModeCallback, client); // BeginAdd double value1 = 100.00D; double value2 = 15.99D; IAsyncResult arAdd = client.BeginAdd(value1, value2, AddCallback, client); Console.WriteLine("Add({0},{1})", value1, value2); // BeginSubtract value1 = 145.00D; value2 = 76.54D; IAsyncResult arSubtract = client.BeginSubtract(value1, value2, SubtractCallback, client); Console.WriteLine("Subtract({0},{1})", value1, value2); // BeginMultiply value1 = 9.00D; value2 = 81.25D; IAsyncResult arMultiply = client.BeginMultiply(value1, value2, MultiplyCallback, client); Console.WriteLine("Multiply({0},{1})", value1, value2); // BeginDivide value1 = 22.00D; value2 = 7.00D; IAsyncResult arDivide = client.BeginDivide(value1, value2, DivideCallback, client); Console.WriteLine("Divide({0},{1})", value1, value2); client.BeginGetOperationCount(GetOperationCountCallback, client); Console.ReadLine(); //Closing the client gracefully closes the connection and cleans up resources client.Close(); } // Asynchronous callbacks for displaying results. static void GetConcurrencyModeCallback(IAsyncResult ar) { string result = ((CalculatorConcurrencyClient)ar.AsyncState).EndGetConcurrencyMode(ar); Console.WriteLine("ConcurrencyMode : {0}", result); } static void GetOperationCountCallback(IAsyncResult ar) { int result = ((CalculatorConcurrencyClient)ar.AsyncState).EndGetOperationCount(ar); Console.WriteLine("OperationCount : {0}", result); } static void AddCallback(IAsyncResult ar) { double result = ((CalculatorConcurrencyClient)ar.AsyncState).EndAdd(ar); Console.WriteLine("Add Result : " + result); } static void SubtractCallback(IAsyncResult ar) { double result = ((CalculatorConcurrencyClient)ar.AsyncState).EndSubtract(ar); Console.WriteLine("Subtract Result : " + result); } static void MultiplyCallback(IAsyncResult ar) { double result = ((CalculatorConcurrencyClient)ar.AsyncState).EndMultiply(ar); Console.WriteLine("Multiply Result : " + result); } static void DivideCallback(IAsyncResult ar) { double result = ((CalculatorConcurrencyClient)ar.AsyncState).EndDivide(ar); Console.WriteLine("Divide Result : " + result); }
Concurrent instance code
Interaction between sessions and InstanceContext settings
When the SessionMode attribute value and InstanceContextMode attribute value are combined, the results of the session or the input channel that does not support the session are supported.