MSMQ in WCF (Two Way Communication Between Client And Server): Part II

Hello Friends, this article is basically an updated version of my previous article, if you haven't look at it kindly go through the following link:
 
 
In the article above there is an issue that the client is unable to determine what has happened to his request, in other words there is no response from the server to the client about his request status. Now in this article we will try to implement a two way communication between the server and the client, in other words whenever the client sends a request to the server, let the server be available or if not then the client request will be maintained in a MSMQ queue and whenever the server becomes available the client request is processed and a status of the request is sent as a response to the client for it. In this case also it may be possible that the client may not be always be available. If the client is not available then the response from the server will be maintained in some other queue and whenever the client becomes available he or she will be able to see the response from the server. This scenario can be implemented by making a transactional queue. In the previous article we created a non-transactional queue. There are various benefits if we create a transactional queue, they are:
  1. Message request or response will be delivered once.
  2. Messages are stored in the queue until the client or server becomes available.
  3. Making use of transactions ensure that the failed messages are totally rolled back to that particular client.
  4. It supports all transaction features such as automatic commit or rollback if any message fails.
  5. We can use Distributed Transaction Management.
  6. For implementing the MSMQ Transactional mode we must set the following things:

    • For making MSMQ queue transactional we must set the second parameter of the MessageQueue.Create method to true in the code file.
    • In the app.config file we must set the exactlyOnce attribute to true for transactional queues.
    • Also in operation contract behavior we must set the following attribute [OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)] that specifies that the transaction must execute inside the same transaction scope and once finished executing should commit automatically.
Now moving towards our topic, what we are going to implement is that we are having a table in my Oracle Database with the name Employee that has certain fields such as (Empid, Name, Address, City and Salary). Now there will be various clients who will try to update their respective records. The client will send their update to the server and upon the successful update of the record the client should get a response from the server that their record has been updated. Now in either of the cases i.e. (client sending an update request to the server or the server sending a response to the client) it may happen that either of the partys may not be available. So when that happens we can use a MSMQ transactional queue to maintain the request and responses of various clients to the server and vice versa.
 
Now to maintain the request of the server and responses from the client we need to maintain two separate queues, one for the request (used by the server to check for requests from clients) and another for responses (used by the client to get the status of their response). There will be two hosts in our application one will be taking care of the server side MSMQ queue requests of the client's and the other will be at the client side that will be responsible for displaying or fetching the responses of the server stored on the client's MSMQ queue. In other words, whatever the client request is, it will be stored on the server's MSMQ queue and whatever the server's response is, it will be stored on the client's MSMQ queue. With this concept, if either of the partys are not available then the request or response will be stored in the respective server or the client's queue and later on when either of the unavailable partys become available it will do further processing of the request or response accordingly.
 
Points to keep in mind
  1. There will be two MSMQ queues that will be used by the server and client respectively for fetching the request (in the case of a server) and for displaying the message (in the case of clients).
  2. There will be two service hosts, one will be at the server side (the actual server that will update the data in the database) and the other will be at the client side that will display the status of the response of what had happend to his request.
  3. Both the server and the client service host will be tied up. i.e both will be referencing each other so that they can transfer messages to each other and the messages can be displayed on their respective screens.
  4. In this case referencing means both will have the WSDL of each other's service. As I said, there will be two services, one will be the actual server that will take care of updating the record in the database and the other will be the client server where the status of the update will be displayed.
  5. All the operation contracts under both services will be executed in the transactional mode to maintain reliability and consistency.
  6. Now in the following I'm providing the name of the servers and their service contract, operation contract and their host server names.

    1. For Server Side We have used EmpService that implements IEmployee Service contract that contains UpdateEmployeeDetails as the operation contract.
    2. For ClientFlashStatus We have used FlashStatusService that implements an IFlashStatus Service Contract that contains UpdateStatus as the operation contract.
    3. EmpUpdateServer (the actual Server) is the server that will be hosting our EmpService.
    4. FlashStatusHost (the client Server) will be the server that will be hosting our FlashStatusService.
     
  7. So the hierarchy of our application is something like the following:

    MSMQ1.jpg
Now if you are familiar with what we are going to do we can move further with our code explaination. I'll try to maintain my explaination as simple as I can. We'll try to complete the demo through a number of steps.
 
I. Oracle Table, Procedures
  1. CREATE TABLE HQM_ADMIN.EMPLOYEE  
  2. (  
  3.   EMPID    VARCHAR2(20 BYTE),  
  4.   NAME     VARCHAR2(30 BYTE),  
  5.   ADDRESS  VARCHAR2(30 BYTE),  
  6.   CITY     VARCHAR2(30 BYTE),  
  7.   SALARY   NUMBER  
  8. )
Procedures
  1. --Procedure for checking employee existence.      
  2.             CREATE OR REPLACE procedure HQM_ADMIN.prc_CheckEmployeeExists      
  3.             (      
  4.                         v_eid varchar,      
  5.                         v_exists out varchar      
  6.             )      
  7.             as      
  8.             v_count number:=0;      
  9.             begin      
  10.                         select count(*) into v_count from Employee where Empid=v_eid;      
  11.                            if(v_count>0)      
  12.                             then      
  13.                                 v_exists:='true';      
  14.                           else       
  15.                                  v_exists:='false';      
  16.                         end if;      
  17.             end;      
  18.       
  19.             //Procedure for updating a record in the table.      
  20.             CREATE OR REPLACE procedure HQM_ADMIN.prc_UpdateEmpDetails      
  21.      (      
  22.            eid varchar,      
  23.            ename varchar,      
  24.            eadd varchar,      
  25.            ecity varchar,      
  26.            esal number      
  27.      )      
  28.      as      
  29.      begin      
  30.            update employee      
  31.            set Name=ename,Address=eadd,City=ecity,Salary=esal      
  32.            where empid=eid;      
  33.      end;
II. WCF Service
 
1. First of all for creating any WCF app as we all know we require a service contract and a service. The following is the code for that. I've created a service contract with the name IEmployee (which basically has one "OperationContract(IsOneWay=true)" named UpdateEmployeeDetails) and a service with the name EmpService that implements an IEmployee service contract.
 
IEmployee service contract
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.ServiceModel;  
  6. namespace EmployeeUpdateReportComponent  
  7. {  
  8.       [ServiceContract]  
  9.       public interface IEmployee  
  10.       {  
  11.               [OperationContract(IsOneWay = true)]  
  12.               void UpdateEmployeeDetails(string eid, string ename, string eadd, string ecity,       double salary, string reportUpdateStatusTo);  
  13.       }  
  14. }  
EmpService.cs
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Data;  
  6. using System.Transactions;  
  7. using System.ServiceModel;  
  8. using System.Data.OracleClient;  
  9. //FlashStatusService Reference added by downloading the wsdl of FlashStatusService  
  10. using EmployeeUpdateReportComponent.FlashStatusServiceRef;  
  11. namespace EmployeeUpdateReportComponent  
  12. {  
  13.     public class EmpService : IEmployee  
  14.     {  
  15.         private string _dbCon = "DATA SOURCE=XXX;WORD=XXX;PERSIST SECURITY INFO=True;USER ID=XXX";  
  16.         OracleConnection con;  
  17.         OracleCommand cmd;  
  18.         //Specifying that the Operation should execute inside a transaction and should automatically commit itself if successfull.  
  19.         //The Transaction will be a distributed transaction in this case.  
  20.         [OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)]  
  21.         public void UpdateEmployeeDetails(string eid, string ename, string eadd, string ecity, double esalary, string reportUpdateStatusTo)  
  22.         {  
  23.             Console.WriteLine("Processing Employee: " + eid + " details");  
  24.             con = new OracleConnection(_dbCon);  
  25.             if (CheckEmployeeExists(eid, con))  
  26.             {  
  27.                 cmd = new OracleCommand("prc_UpdateEmpDetails", con);  
  28.                 cmd.CommandType = CommandType.StoredProcedure;  
  29.                 cmd.Parameters.AddWithValue("eid", eid);  
  30.                 cmd.Parameters.AddWithValue("ename", ename);  
  31.                 cmd.Parameters.AddWithValue("eadd", eadd);  
  32.                 cmd.Parameters.AddWithValue("ecity", ecity);  
  33.                 cmd.Parameters.AddWithValue("esal", esalary);  
  34.                 con.Open();  
  35.                 int rows = cmd.ExecuteNonQuery();  
  36.                 con.Close();  
  37.                 //Reference of FlashStatusService to display the status of the update to the respective Employee.  
  38.                 FlashStatusClient flashClient = new FlashStatusClient(new NetMsmqBinding(), new EndpointAddress(reportUpdateStatusTo));  
  39.                 //use the same transaction scope for returning the status to the user.  
  40.                 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))  
  41.                 {  
  42.                     string updateStatus = rows > 0 ? "Updated" : "Pending";  
  43.                     //calling the flash status UpdateStatus operation contract to display a status to the client for his/her request by sing the necessary parameters.  
  44.                     flashClient.UpdateStatus(eid, ename, eadd, ecity, esalary, updateStatus);  
  45.                     //Commit the Transaction  
  46.                     scope.Complete();  
  47.                     Console.WriteLine("Done Processing Of Employee: " + eid);  
  48.                 }  
  49.             }  
  50.         }  
  51.         /// <summary>  
  52.         /// This function check whether the employee exists in the table or not and return a boolean value.  
  53.         /// </summary>  
  54.         /// <param name="eid">Emp Id</param>  
  55.         /// <param name="con">OracleConnection object</param>  
  56.         /// <returns>True or False</returns>  
  57.         private bool CheckEmployeeExists(string eid, OracleConnection con)  
  58.         {  
  59.             if (con.ConnectionString == "")  
  60.                 con = new OracleConnection(_dbCon);  
  61.             cmd = new OracleCommand("prc_CheckEmployeeExists", con);  
  62.             cmd.CommandType = CommandType.StoredProcedure;  
  63.             cmd.Parameters.AddWithValue("v_eid", eid);  
  64.             OracleParameter para = new OracleParameter();  
  65.             para.ParameterName = "v_exists";  
  66.             para.Size = 10;  
  67.             para.OracleType = OracleType.VarChar;  
  68.             para.Direction = ParameterDirection.Output;  
  69.             cmd.Parameters.Add(para);  
  70.             con.Open();  
  71.             OracleDataReader dr = cmd.ExecuteReader();  
  72.             string returnValue = para.Value.ToString();  
  73.             con.Close();  
  74.             if (returnValue != "" && returnValue == "true")  
  75.                 return true;  
  76.             else  
  77.                 return false;  
  78.         }  
  79.     }  
  80. }  
3. Now we will try to create a server (Self Hosted) for our EmpService, in our case "EmployeeServerUpdateHost" will be our host.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Messaging;  
  6. using System.Transactions;  
  7. using System.Configuration;  
  8. using System.ServiceModel;  
  9. using EmployeeUpdateReportComponent;  
  10.   
  11. namespace EmployeeServerUpdateHost  
  12. {  
  13.     class EmpUpdateServer  
  14.     {  
  15.         static void Main(string[] args)  
  16.         {  
  17.             //read the queueName specified in the AppSettings of the App.Config file.  
  18.             string queueName = ConfigurationManager.AppSettings["queueName"].ToString();  
  19.             //Check for queue existence if it does not exists then create the queue.  
  20.             if (!MessageQueue.Exists(queueName))  
  21.             {  
  22.                 //Here we are creating a queue with the specified queue name   
  23.                 //and making the queue as transactional by specifying true in the second parameter  
  24.                 MessageQueue.Create(queueName, true);  
  25.             }  
  26.             using (ServiceHost host = new ServiceHost(typeof(EmpService)))  
  27.             {  
  28.                 host.Open();  
  29.                 Console.WriteLine("Server is up and running on port no: 57829");  
  30.                 Console.WriteLine("Press any key to terminate");  
  31.                 Console.ReadKey();  
  32.                 host.Close();  
  33.             }  
  34.         }  
  35.     }  
  36. }  
App.Config File For the Same
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <appSettings>  
  4.     <!-- Use appSetting to configure MSMQ queue name. -->  
  5.     <add key="queueName" value=".\private$\UpdateEmpTwoWay/UpdateEmp" />  
  6.   </appSettings>  
  7.   <system.serviceModel>  
  8.     <diagnostics performanceCounters="All" />  
  9.     <services>  
  10.       <service name="EmployeeUpdateReportComponent.EmpService" behaviorConfiguration="myBehavior">  
  11.    
  12.         <!--Address attribute specifies the name of the MSMQ Queue.-->  
  13.         <endpoint name="msmqTransactionEndpoint" address="net.msmq://localhost/private/UpdateEmpTwoWay/UpdateEmp" binding="netMsmqBinding"  
  14.                                                                           bindingConfiguration="myMSMQ" contract="EmployeeUpdateReportComponent.IEmployee"/>  
  15.         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>  
  16.         <host>  
  17.           <baseAddresses>  
  18.             <add baseAddress="net.msmq://localhost/private/"/>  
  19.             <!--Both Mex and HttpBinding uses http://localhost:8888 port-->  
  20.             <add baseAddress="http://localhost:57829"/>  
  21.           </baseAddresses>  
  22.         </host>  
  23.       </service>  
  24.     </services>  
  25.     <bindings>  
  26.       <!--The property exactlyOnce=false means that i am using non transactional queue. The property is by default true.-->  
  27.       <netMsmqBinding>  
  28.         <binding name="myMSMQ" exactlyOnce="true" receiveErrorHandling="Move">  
  29.           <!--If we donot set the security mode to none then the following error occurs. -->  
  30.            <!--      Binding validation failed because the binding's MsmqAuthenticationMode property is set to  -->  
  31.             <!--     WindowsDomain but MSMQ is installed with Active Directory integration disabled.  -->  
  32.           <!--       The channel factory or service host cannot be opened.  
  33.           -->  
  34.           <security mode="Transport"/>  
  35.         </binding>  
  36.       </netMsmqBinding>  
  37.     </bindings>  
  38.     <behaviors>  
  39.       <serviceBehaviors>  
  40.         <behavior name="myBehavior">  
  41.           <serviceMetadata httpGetEnabled="true"/>  
  42.           <!--This is for enabling an exception-->  
  43.           <serviceDebug includeExceptionDetailInFaults="true"/>  
  44.         </behavior>  
  45.       </serviceBehaviors>  
  46.     </behaviors>  
  47.   </system.serviceModel>  
  48. </configuration>  
4. Now we will try to create the client service contract and the service that will help us to display/flash a status message to the client. In our case the component name would be ClientFlashStatusComponent; see:
 
IflashStatus.cs (ServiceContract)
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.ServiceModel;  
  6.   
  7. namespace ClientFlashStatusComponent  
  8. {  
  9.     [ServiceContract]  
  10.     public interface IFlashStatus  
  11.     {  
  12.         [OperationContract(IsOneWay = true)]  
  13.         void UpdateStatus(string eid, string ename, string eadd, string ecity, double esalary, string updateStatusReport);  
  14.     }  
  15. }  
FlashStatusService.cs (Service)
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.ServiceModel;  
  6. using System.Transactions;  
  7.   
  8. namespace ClientFlashStatusComponent  
  9. {  
  10.     public class FlashStatusService : IFlashStatus  
  11.     {  
  12.         [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]  
  13.         public void UpdateStatus(string eid, string ename, string eadd, string ecity, double esalary, string updateStatusReport)  
  14.         {  
  15.             Console.WriteLine("Update Status Report Of Employee Details.");  
  16.             Console.WriteLine("\n\n************************************\n");  
  17.             Console.WriteLine("Employee Updated Details are");  
  18.             Console.WriteLine("Emp ID: " + eid);  
  19.             Console.WriteLine("Name: " + ename);  
  20.             Console.WriteLine("Address: " + eadd);  
  21.             Console.WriteLine("City: " + ecity);  
  22.             Console.WriteLine("Salary: " + esalary);  
  23.             Console.WriteLine("---------------------------------------------\n Update Status\n\n");  
  24.             Console.WriteLine("Update Status: " + updateStatusReport);  
  25.             Console.WriteLine("\n==================================");  
  26.         }  
  27.     }  
  28. }  
5. And finally we will create a host for the client service that will host our client application. In our case our host name is ClientStatusFlashHost. It has a reference to our server service EmpService because from here the client will be calling the updateEmployeeDetail operationcontract and will get the response on the same screen.
 
FlashStatusHost.cs (Client Service Host)
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Messaging;  
  6. using System.Transactions;  
  7. using System.ServiceModel;  
  8. using ClientFlashStatusComponent;  
  9. using System.Net;  
  10. using System.Configuration;  
  11. //Reference to EmpService by downloading the wsdl of EmpService  
  12. using ClientStatusFlashHost.EmpServiceReference;  
  13.   
  14. namespace ClientStatusFlashHost  
  15. {  
  16.     class FlashStatusHost  
  17.     {  
  18.         static string queueName = "";  
  19.   
  20.         static FlashStatusHost()  
  21.         {  
  22.             //Get the local computer name.  
  23.             string hostName = Dns.GetHostName();  
  24.   
  25.             //creating a new queue name if the queue doest exists. It is basically used if the program is run on any machine  
  26.             // then a name of the queue nameOfTheMachine/UpdateEmpTwoWay/UpdateStatus. Basically useful for   
  27.             //network environment for every new request from new computer a new queue will be created on that system, the only  
  28.             //requirement is msmq needs to be installed. If you dont want to test on the network then just read the queue name from the  
  29.             //app.config file and comment the lines   
  30.                 //string hostName = Dns.GetHostName();    
  31.                 //queueName = queueName.Replace(".", hostName);  
  32.   
  33.             queueName = ConfigurationManager.AppSettings["queueName"].ToString();  
  34.             queueName = queueName.Replace(".", hostName);  
  35.         }  
  36.    
  37.         /// <summary>  
  38.         /// This function returns the no/length of messages in the particular queue.  
  39.         /// </summary>  
  40.         /// <param name="queueName"></param>  
  41.         /// <returns></returns>  
  42.         public static int GetMessagesInQueueLength(string queueName)  
  43.         {  
  44.             MessageQueue queue = new MessageQueue(queueName);  
  45.             return queue.GetAllMessages().Length;  
  46.         }   
  47.   
  48.         /// <summary>  
  49.         /// This function will create the message queue if the queue does not exists or   
  50.         /// else it will return the instance of the existing queue if it already exists.  
  51.         /// </summary>  
  52.         /// <returns>Message Queue object.</returns>  
  53.         public static MessageQueue GetMessageQueue()  
  54.         {  
  55.             if (!MessageQueue.Exists(queueName))  
  56.                 //Here we are creating a queue with the specified queue name  and making the queue as transactional by specifying true in the second parameter  
  57.                 return MessageQueue.Create(queueName, true);  
  58.             else  
  59.             {  
  60.                 MessageQueue queue = new MessageQueue(queueName);  
  61.                 return queue;  
  62.             }  
  63.         }  
  64.   
  65.         static void Main(string[] args)  
  66.         {  
  67.             //read the queueName specified in the AppSettings of the App.Config file.  
  68.             //string queueName = ConfigurationManager.AppSettings["queueName"].ToString();   
  69.             using (ServiceHost host = new ServiceHost(typeof(FlashStatusService)))  
  70.             {  
  71.                 //Get the instance of the MessageQueue object here  
  72.                 GetMessageQueue();  
  73.                 //open the service host  
  74.                 host.Open();  
  75.                 if (GetMessagesInQueueLength(queueName) == 0)  
  76.                 {  
  77.                     string eid, ename, eaddress, ecity;  
  78.                     double esalary;  
  79.   
  80.                     EmployeeClient objClient = new EmployeeClient("msmqTransactionEndpoint");  
  81.   
  82.                     Console.WriteLine("Enter Eid:");  
  83.                     eid = Console.ReadLine();  
  84.                     Console.WriteLine("Enter EName:");  
  85.                     ename = Console.ReadLine();  
  86.                     Console.WriteLine("Enter EAddress:");  
  87.                     eaddress = Console.ReadLine();  
  88.                     Console.WriteLine("Enter ECity:");  
  89.                     ecity = Console.ReadLine();  
  90.                     Console.WriteLine("Enter ESalary:");  
  91.                     esalary = Double.Parse(Console.ReadLine());  
  92.   
  93.                     using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))  
  94.                     {  
  95.                         objClient.UpdateEmployeeDetails(eid, ename, eaddress, ecity, esalary, "net.msmq://localhost/private/UpdateEmpTwoWay/UpdateStatus");  
  96.                         scope.Complete();  
  97.                     }  
  98.                     //Close down the client.  
  99.                     objClient.Close();  
  100.   
  101.                     Console.WriteLine();  
  102.                     Console.WriteLine("Wait until server Responds Or");  
  103.                     Console.WriteLine("Press <ENTER> to terminate client.");  
  104.                     Console.ReadLine();  
  105.                     // Close the ServiceHost to shutdown the service.  
  106.                     host.Close();  
  107.                 }  
  108.                 Console.ReadLine();  
  109.             }  
  110.         }  
  111.     }  
  112. }  
App.Config For the same
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <appSettings>  
  4.     <add key="queueName" value=".\private$\UpdateEmpTwoWay/UpdateStatus"/>  
  5.   </appSettings>  
  6.   <system.serviceModel>  
  7.     <diagnostics performanceCounters="All" />  
  8.     <services>  
  9.       <service name="ClientFlashStatusComponent.FlashStatusService" behaviorConfiguration="myBehavior">  
  10.         <!--Address attribute specifies the name of the MSMQ Queue.-->  
  11.         <endpoint name="Operations" address="net.msmq://localhost/private/UpdateEmpTwoWay/UpdateStatus" binding="netMsmqBinding"  
  12.         bindingConfiguration="myMSMQ" contract="ClientFlashStatusComponent.IFlashStatus">  
  13.           <identity>  
  14.             <dns value="localhost"/>  
  15.           </identity>  
  16.         </endpoint>  
  17.         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>  
  18.         <host>  
  19.           <baseAddresses>  
  20.             <add baseAddress="net.msmq://localhost/private/"/>  
  21.             //clientFlashStatus Address, this is required while downloading the wsdl of the Service  
  22.             <add baseAddress="http://localhost:32578"/>  
  23.           </baseAddresses>  
  24.         </host>  
  25.       </service>  
  26.     </services>  
  27.     <bindings>  
  28.       <netMsmqBinding>  
  29.         <binding name="myMSMQ" exactlyOnce="true">  
  30.           <security mode="Transport" />  
  31.         </binding>  
  32.         <binding name="msmqTransactionEndpoint" closeTimeout="00:01:00"  
  33.           openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"  
  34.           deadLetterQueue="System" durable="true" exactlyOnce="true" maxReceivedMessageSize="65536"  
  35.           maxRetryCycles="2" receiveErrorHandling="Fault" receiveRetryCount="5"  
  36.           retryCycleDelay="00:30:00" timeToLive="1.00:00:00" useSourceJournal="false"  
  37.           useMsmqTracing="false" queueTransferProtocol="Native" maxBufferPoolSize="524288"  
  38.           useActiveDirectory="false">  
  39.           <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"  
  40.             maxBytesPerRead="4096" maxNameTableCharCount="16384" />  
  41.           <security mode="Transport">  
  42.             <transport msmqAuthenticationMode="WindowsDomain" msmqEncryptionAlgorithm="RC4Stream"  
  43.               msmqProtectionLevel="Sign" msmqSecureHashAlgorithm="Sha1" />  
  44.             <message clientCredentialType="Windows" />  
  45.           </security>  
  46.         </binding>  
  47.       </netMsmqBinding>  
  48.     </bindings>  
  49.     <behaviors>  
  50.       <serviceBehaviors>  
  51.         <behavior name="myBehavior">  
  52.           <serviceMetadata httpGetEnabled="true"/>  
  53.           <!--This is for enabling an exception to be shown to the user which might occur in service.-->  
  54.           <serviceDebug includeExceptionDetailInFaults="true"/>  
  55.         </behavior>  
  56.       </serviceBehaviors>  
  57.     </behaviors>  
  58.   </system.serviceModel>  
  59. </configuration>  
Note: To add the reference for EmpService you will need to run the EmployeeServerUpdateHost that is responsibile for hosting the EmpService. So that the WSDL of the service can be downloaded. Now for running the EmployeeServerUpdateHost, you will need to go to the bin folder of it and double-click the .exe file of it to ensure that your console screen displays the following message:
 
MSMQ2.jpg
 
MSMQ3.jpg 
 
Let it be running and now you can add the reference of your EmpService in your ClientStatusFlashHost by right-clicking on it then selecting "Add Service Reference" and type in the Address we specified in the App.Config file of our EmployeeServerUpdateHost. In other words, in our case it would be <add baseAddress="http://localhost:57829"/> our EmployeeServerUpateHost is hosted at the above address.
 
After downloading the service in the ClientFlashStatusHost, there will be a change in the app.config file of your ClientFlashStatusHost with the following addition of lines.
  1. <client>  
  2.   <endpoint address="net.msmq://localhost/private/UpdateEmpTwoWay/UpdateEmp"  
  3.     binding="netMsmqBinding" bindingConfiguration="msmqTransactionEndpoint"  
  4.     contract="EmpServiceReference.IEmployee" name="msmqTransactionEndpoint" />  
  5. </client>  
6. Now, in the same manner, you will need to add the service reference of your ClientFlashStatusHost in your EmpService Project.
 
For adding the reference, go to the bin folder of ClientFlashStatusHost and double-click the .exe file:
 
MSMQ4.jpg 
 
It will prompt you like the following:
 
MSMQ5.jpg 
 
Don't type anything in it, go to Visual Studio where your EmployeeUpdateReportComponent is there, right-click on the EmployeeUpdateReportComponent project and click "Add ServiceReference" then type in the WSDL path of the ClientFlashStatusHost. In our case it would be:
 
<add baseAddress="http://localhost:32578"/>
 
That is what we specified in the App.config file of ClientFlashStatusHost.
 
7. By following the steps above you have created a reference between your EmpService and ClientFlashStatusHost service by adding the reference of each other to each solution.Now for EmpService, ClientFlashStatusHost would be the client and for ClientFlashStatusHost EmpService would be the client. You can check this in the app.config files.
 
8. Before running the application kindly start the Distributed Transaction Coordinator service from services.msc.
 
9. We are finally done with our application, now we can test it. The output of the application can be seen in 3 ways.
  1. When both the server and the client are online/available.
  2. When the server is unavailable and the client sends a request for update (request would be stored in the server's MSMQ queue).
  3. Finally, when the server becomes online and the client is offline. (If there are any requests from the client in the server's MSMQ queue then they will be processed by the server and the appropriate response would be delivered to the client's MSMQ queue. Later on when the client becomes available he/she would be able to see the server response.)
Note:
 
When for the first time you run the application, it will create two queue in the MSMQ of your computer. You can check it by going to the following path:
 
open "Administrative Tools" from "Control Panel"; go to "Computer Management". Expand "Services and Applications". You fill two queues are being generated:
  1. updateemptwoway/updateemp (Server queue)
  2. updateemptwoway/updatestatus (Client Queue)

Output Phase1: Server and client are both available.
 
The Server is online.
 
MSMQ6.jpg 
 
The client appears and starts updating the record as per his/her id; the following screenshot displays the client's screen:
 
MSMQ7.jpg 
 
Since both are online the server screen will be displaying the following message after it receives the request from the client:
 
MSMQ8.jpg 
 
It says processing until it updates records and finally displays "Done Processing of Employee Code".
 
And the client screen would be getting the following message:
 
MSMQ9.jpg 
 
Since the server was online and was free, it responded quickly to the client's request and provided the status of the update to the client there and then.
 
Output Phase II: Server is unavailable and the client sends a request.
 
In this case, you will need to close the server. So that whatever request was sent by the client will be stored in the server's MSMQ queue.
 
MSMQ10.jpg 
 
Close the Server .exe file.
 
After closing, try to run the "ClientFlashStatuHost.exe" file by double-clicking it in the bin folder.
 
MSMQ11.jpg 
 
Since the server is unavailable, the client request would be stored in the server's MSMQ queue. The following snapshot displays that:
 
MSMQ12.jpg 
 
Now run the server exe file; you fill that the message from the server's MSMQ queue will be read by the server and it will do the required processing and send a response to the client.
 
MSMQ13.jpg 
 
If the client is available then he/she will be able to see the response or else if he/she is not available then the response message will be stored in the client's MSMQ queue. When later the client becomes online he/she will be able to see the message.
 
MSMQ14.jpg 
 
Output Phase 3: Client sends request and becomes unavailable (i.e. the server is online and the client is offline)
 
For this, start the client exe then type the update request and you will see the following screen (ensure that the server is not running):
 
MSMQ15.jpg 
 
Now here the client's request will be stored in the server's MSMQ queue as we saw in the output phase II. Now close the client screen and start the server.
 
MSMQ16.jpg 
 
Over here the server sent a response to the client for the same request. The response will be stored in the client MSMQ queue.
 
The following screenshot displays the same.
 
MSMQ17.jpg 
 
Later, when the client becomes available, the response will be displayed to the client.
 
MSMQ18.jpg 
 
Hope you found the article interesting and it may help you in your project.


Similar Articles