Access PerSession service simultaneously in WCF using C #

1.) I have a basic Processing method that takes a string as arguments and this string contains a number of tasks.

2.) I have another Status method that tracks the first method using the two variables TotalTests and CurrentTest. which will be changed each time using the loop in the first method (Processing).

3.) When several clients make a call in parallel with my web service to call a processing method, passing a line that has different tasks will take more time to process. therefore, on average, while clients will use the second thread to call the Status method in the web service to get the status of the first method.

4.), when point 3 is made, all clients should receive variables (TotalTests, CurrentTest) in parallel with the fact that they are mixed with other client requests.

5.) The code that I provided below causes the results of the variables to be mixed for all clients when I make them static. If I delete static for variables, then the clients just get all 0 for these 2 variables, and I cannot fix it. Please see the code below.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] public class Service1 : IService1 { public int TotalTests = 0; public int CurrentTest = 0; public string Processing(string OriginalXmlString) { XmlDocument XmlDoc = new XmlDocument(); XmlDoc.LoadXml(OriginalXmlString); this.TotalTests = XmlDoc.GetElementsByTagName("TestScenario").Count; //finding the count of total test scenarios in the given xml string this.CurrentTest = 0; while(i<10) { ++this.CurrentTest; i++; } } public string Status() { return (this.TotalTests + ";" + this.CurrentTest); } } 

server configuration

 <wsHttpBinding> <binding name="WSHttpBinding_IService1" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="true" /> <security mode="Message"> <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" /> <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true" /> </security> </binding> </wsHttpBinding> 

Client configuration

 <wsHttpBinding> <binding name="WSHttpBinding_IService1" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="true" /> <security mode="Message"> <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" /> <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true" /> </security> </binding> </wsHttpBinding> 

Below is the code of my client

 class Program { static void Main(string[] args) { Program prog = new Program(); Thread JavaClientCallThread = new Thread(new ThreadStart(prog.ClientCallThreadRun)); Thread JavaStatusCallThread = new Thread(new ThreadStart(prog.StatusCallThreadRun)); JavaClientCallThread.Start(); JavaStatusCallThread.Start(); } public void ClientCallThreadRun() { XmlDocument doc = new XmlDocument(); doc.Load(@"D:\t72CalculateReasonableWithdrawal_Input.xml"); bool error = false; Service1Client Client = new Service1Client(); string temp = Client.Processing(doc.OuterXml, ref error); } public void StatusCallThreadRun() { int i = 0; Service1Client Client = new Service1Client(); string temp; while (i < 10) { temp = Client.Status(); Thread.Sleep(1500); Console.WriteLine("TotalTestScenarios;CurrentTestCase = {0}", temp); i++; } } } 

Can anyone help.

+4
source share
2 answers

Firstly, since you need to access the service at the same time when the service processes the first client call (Processing), you need to change the concurrency service mode to several.

You also want to save every client processing status, so you need to set the instance context mode in PerSession.

 [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode= InstanceContextMode.PerSession)] 

Note

  • Default InstanceContextMode - PerSession
  • By default, ConcurrencyMode is Single

You can do the following to make sure your configuration is compatible with the PerSession InstanceContextMode, using this method, WCF will throw an exception at run time if necessary

 [ServiceContract(SessionMode=SessionMode.Required)] 

Note With InstanceContextMode.PerSession, you will get a different instance for each proxy created

Thus, you only need one instance of "Service1Client" for each client, which you will call it the Method method, and also get the status from it.

Also, for virtual heavy processing, you can use Thread.Sleep (millisecond) for the test, offered only in the "Processing" (Service-Side) method.

For a client application, if you want to call the "Processing" method, and then using the "Status" method to get the status, you need to call the "Asynchronous" method.

1.Click on the service link in the explorer solution and select "Configure service link", then check "Generate asynchronous operation" and click "OK".

2. Change your client code as follows

 static void Main(string[] args) { StartProcessing(); StatusReport(); Console.ReadLine(); } static ServiceClient Client = new ServiceClient(); private static bool Completed = false; public static void StartProcessing() { XmlDocument doc = new XmlDocument(); doc.Load(@"D:\t72CalculateReasonableWithdrawal_Input.xml"); bool error = false; Client.ProcessingCompleted += Client_ProcessingCompleted; Client.ProcessingAsync(doc.OuterXml); Console.WriteLine("Processing..."); } static void Client_ProcessingCompleted(object sender, ProcessingCompletedEventArgs e) { // processing is completed, retreive the return value of Processing operation Completed = true; Console.WriteLine(e.Result); } public static void StatusReport() { int i = 0; string temp; while (!Completed) { temp = Client.Status(); Console.WriteLine("TotalTestScenarios;CurrentTestCase = {0}", temp); Thread.Sleep(500); i++; } } 
+1
source

PerSession will not cause your static variables to not be shared with object instances. The only thing PerSession context mode PerSession is control the lifetime of an object.

With PerSession WCF does not destroy the service object until the session ends. A session can be closed explicitly by the client or timeout (10 minutes by default). Each subsequent call from a client with the same session identifier will be routed by WCF to an existing object.

Variables must not be static to prevent sharing across service instances. The state of the variables will be maintained by WCF as long as you use InstanceContextMode.PerSession and a binding that supports the session.

 public int TotalTests = 0; public int CurrentTest = 0; 

I would also add SessionMode.Required for the contract to make sure the service is configured correctly.

  [ServiceContract(SessionMode = SessionMode.Required )] 
0
source

All Articles