Duplex Service Using WCF

In this article, you will learn about Duplex Service, using WCF.

Introduction

WCF as we all know is used to develop distributed and inter-operable applications in which it provides a few message exchange patterns. Now, what is message exchange pattern?It is the manner in which communication occurs between the client and server. A few of the message exchange patterns supported by WCF are Request- Response, and one way is Duplex. In this article, let us try to explore the Duplex pattern provided by the WCF .

What is Duplex message exchange pattern ?

This is the pattern in which the client and Server can initiate communication between one other

We can say it is the combination of the One- Way Request -Response. It can be used in a situation, where we want to send the notification to the client in case of heavy processing.


The diagram given above explains how the communication occurs in the Duplex. In this, the client initiates the communication on the Server along with the Response, which also forms the callback channel, which will update the client with the needed things.

Let's move towards my implementation of the Duplex.

Why Duplex?

In one of my applications, we have the provision to bulk process the invoice for the payments.

Tradition Request Response approach uses basichttpBinding, as it will process all the invoices and send the processing result as part of the Response, so the client end doesn't know what is the status of the exact payment or how many payments happened, when any error occurred in between, so we decided to move to Duplex, where we can get all the data. 

Let's see how we can develop Duplex Service step by step.

  • Open Visual Studio.
  • Add ASP.NET Web Application (Preferably, I added Empty Website to avoid the unnecessary things).
  • Name the Website, as shown below.



  • Add the new WCF Service name as PaymentService.


Now, come to the contracts in the Services

ServiceContract 
  1. using System.ServiceModel;  
  2. using System.Text;  
  3. [ServiceContract]  
  4. public interface IPaymentService  
  5. {  
  6.     [OperationContract]  
  7.     void DoPayment(Payment objPayment);  
  8. }  

This is the default Service contract, which is added by default. Here, we have operation contract DoPayment, which accepts the class Payment till this service is basic service, which will work as normal WCF Service, which is capable of request response. To make this, we need to do some changes to this.

Adding Call-back Contract 

  1. [ServiceContract(CallbackContract = typeof(ICallBackPaymetDetails))]  
  2. public interface IPaymentService
  3. {  
  4.     [OperationContract]  
  5.     void DoPayment(Payment objPayment);  
  6. }    
  7. public interface ICallBackPaymetDetails  
  8. {  
  9.      [OperationContract(IsOneWay = true)]  
  10.     void SendStatusUpdate(Payment ObjPayment);  
  11. }  

Here, the interface ICallBackPaymentDetails which acts as the callback Interface, which will send the data to the client, which updates the status on each payment .

Adding DataContract

  1. [DataContract]  
  2. public class Payment  
  3. {  
  4.     public Payment(){}  
  5.     [DataMember]  
  6.     public string TransactionID { get; set; }  
  7.     [DataMember]  
  8.     public string Status { get; set; }  
  9.     [DataMember]  
  10.     public string StatusMessage { get; set; }  
  11. }   

Note- Here, to mark the class as [DataContract] properties as the [DataMember], which will be used by serialization engine to serialize and deserialize these properties.

Adding Implementation Class for the Service

 

  1. [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]  
  2. public class PaymentService : IPaymentService  
  3. {  
  4.  public void DoPayment(Payment objPayment)  
  5.     {  
  6.        ICallBackPaymetDetails Callbackchannel=OperationContext.Current.GetCallbackChannel<ICallBackPaymetDetails>(); Callbackchannel.SendStatusUpdate(new Payment() { Status = "A", TransactionID = "2", StatusMessage = "Approved" });  
  7.          
  8.     }  
  9. }   

This implementation implements the DoPayment method, which is the Operation Contract of the Service. In this, the main thing to notice here is the InstanceContext mode is set to PerCall, which will create the Service Instance on each call. Now, coming to the method Implementation, we are creating the call back channel to the Client, which has initiated the operation.

OperationContext.Current.GetCallbackChannel<ICallBackPaymetDetails>(); This will return the current client, which is connected to the Server from where the request has come This will call the SendStatusUpdate(), which will be received at the client end.

Configuration changes In Web.Config 

  1. <system.serviceModel>  
  2.    <behaviors>  
  3.      <serviceBehaviors>  
  4.        <behavior name="myduplex">  
  5.          <serviceMetadata httpGetEnabled="True" />  
  6.          <serviceDebug includeExceptionDetailInFaults="false" />  
  7.        </behavior>  
  8.      </serviceBehaviors>  
  9.    </behaviors>  
  10.   
  11.    <services>  
  12.     <!--Remember service name is always name of the implelementation-->   
  13.      <service name="PaymentService" behaviorConfiguration="myduplex">  
  14.        <endpoint name="PaymentDuplexEndPoint" contract="IPaymentService"binding="wsDualHttpBinding"/>  
  15.         <endpoint name ="MetaDataTcpEndpoint” address="mex" binding="mexHttpBinding”                   contract="IMetadataExchange"/>  
  16.      </service>  
  17.    </services>  
  18.  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />  
  19.  </system.serviceModel>   

One thing to notice is that in this configuration is the binding, which we have used in this configuration

This is the WsDualHttpBinding. This binding is designed for use with Duplex Service contracts, which allows both the Services and clients to send and receive the messages.

This is all about creating Service. Summarizing the points to create the Duplex Service are shown below.

  • Add the Service and add the attribute (CallbackContract = typeof(ICallBackPaymetDetails)).
  • Add DataContract according to your need.
  • Implement the service contract and create the callback channel.
  • Modify the web.Config to accept the WsDualHttpBinding. Do the configuration, as shown in the above file.
  • Get the Current Client Callback channel and call the CallBack Method, which will invoke the particular client.

Creating Client

Now, we are ready with the Service. We need the client, which will consume this Service to use the client.

Let's follow the process given below.

  • Add one Console Application and name it as PaymentClient.
  • Right click on the Project-> Add Service Reference--> Add Address--> Go-->OK.

(In order to detect the Address where the Service is hosted, right click on your .svc file and view in the Browser.

It will give you the address, where the Service is hosted.)

Below is the screenshot, which shows how to add the Reference in the client.


App.Config

When we add the Reference, it adds the app.config, which will hold the configuration data, which is shown below.

  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.     <system.serviceModel>  
  4.         <bindings>  
  5.             <wsDualHttpBinding>  
  6.                 <binding name="PaymentDuplexEndPoint" />  
  7.             </wsDualHttpBinding>  
  8.         </bindings>  
  9.         <client>  
  10.             <endpoint address="http://localhost:58407/PaymentService.svc"  
  11.                 binding="wsDualHttpBinding" bindingConfiguration="PaymentDuplexEndPoint"  
  12.                 contract="PaymentService.IPaymentService" name="PaymentDuplexEndPoint">  
  13.             </endpoint>  
  14.         </client>  
  15.     </system.serviceModel>  
  16. </configuration>    

This will be added by default, when you add the Service in your application. It specifies the bindings and the endpoint configuration.

Next step is to implement the Callback contract. Remember the CallbackContract ICallBackPaymetDetails.

  1. using PaymentClient.PaymentService;  
  2. namespace PaymentClient  
  3. {  
  4.     class AcceptCallBack:IPaymentServiceCallback  
  5.     {  
  6.         public void SendStatusUpdate(Payment ObjPayment)  
  7.         {  
  8.             Console.Write(GetStatusString(ObjPayment));  
  9.         }  
  10.     public string GetStatusString(Payment Obj)  
  11.         {  
  12.             return Obj.Status + " " + Obj.StatusMessage + " " + Obj.TransactionID+Environment.NewLine;  
  13.         }  
  14.     }  
  15. }   

Class AcceptCallBack implements the IPaymentServiceCallback, which contains our call back method.

SendStatusUpdate and the client receives the notification of the payment that happened at the Server. The main implementation for the processing is given below.

  1. using PaymentClient.PaymentService;  
  2. namespace PaymentClient  
  3. {  
  4.   public  class ProcessPayment  
  5.     {  
  6.       public void DoProcessing()  
  7.       {  
  8.           PaymentServiceClient op = new PaymentServiceClient(new InstanceContext(new AcceptCallBack()));  
  9.           op.DoPayment(new Payment());  
  10.           Console.ReadLine();  
  11.       }  
  12.     }  
  13. }   

Here, the PaymentServiceClient calls the DoPayment (), which is our processing method. Here, the client accepts the InstanceContext as the Implementation class of the Callback Contract. In this way, it forms the callback Channel and processing happens.

Hope you liked the basics of the Duplex Service.

Happy coding.