Click here to Skip to main content
Click here to Skip to main content

WCF - Message Exchange Patterns (MEPs)

By , 30 Mar 2013
Rate this:
Please Sign up or sign in to vote.

Message Exchange Pattern describes how the client and server should exchange messages, and also the MEP will make clear that the client is going to wait for any response from the service or just simply sending is enough ,or the client is expecting any callbacks from the service. 

WCF supports three Message Exchange Patterns (MEPs). They are as follows. 

In this article I'm going to explain all the Message Exchange Patterns with the help of a sample project. I hope you will enjoy this article. Please don't forget to mark your votessuggestions and feedback to improve the quality of this and upcoming articles.

Request-Reply

In a Request-Reply message exchange pattern, a client sends a message to a WCF Service and then waits for a reply. If the service doesn't respond to the client within ReceiveTimeout then the client will receive a TimeoutException. Unless a client invokes the operation asynchronously, the client stops processing until the return message is received, even if the operation return type is void. The below code shows how a operation contract with 'Request-Reply' as message exchange pattern. 

[OperationContract]   
string GetValue(string Key);   
[OperationContract]   
void Log(string Msg);   

Request-Reply means the IsOneWay property is set to false,you do not have to set the IsOneWay property to false because by default it is false. So the above 'GetValue' operation contract can be re-written as below also, 

[OperationContract(IsOneWay = false)]
string GetValue(string Key);  

Unless you specify a different message pattern, even service operations that return void are also Request-Reply. The main advantage using Request-Reply is that SOAP faults can be returned in the response message.

You can perform calls to a service operation either synchronously, where the client blocks until it receives a response from the service or the call times, or asynchronously, where the client makes a call to the service operation, continues working, and receives the response from the service on another thread.

Request-Reply is the default message exchange pattern in WCF and it is used more often than other patterns. All WCF bindings except the MSMQ-based bindings support the Request-Reply MEP. The below diagram shows how a Request-Reply MEP works in a synchronous operation. 

Let's understand more with once simple example, I have created a WCF Service Project and a Windows Project for consuming that wcf services, (Source code attached with this article) 

Now adding one WCF Service to the service project, I have named the service as 'MEPRequestReplyService'. Visual Studio auto generated two class files ('IMEPRequestReplyService.cs' and 'MEPRequestReplyService.svc'). 

I'm adding two OperationContract to my newly created 'IMEPRequestReplyService.cs'

[OperationContract]  
void SendEmail();      
[OperationContract]   
DateTime GetServerTime();   

If you look at the return types one is void and the other one is DateTime, The operations are following Request-Reply MEP as by default IsOneWay is set to false.

Accordingly I have implemented the above methods in 'MEPRequestReplyService.svc'. 

public class MEPRequestReplyService : IMEPRequestReplyService
{        
    public void SendEmail()
    {
        //Implement logic
        Thread.Sleep(500);
        return;
    }
 
    public DateTime GetServerTime()
    {
        return DateTime.Now;
    }
} 

In 'SendEmail()' I have added Thread.Sleep for a small delay, You can implement your own logic in any methods.  

I'm just going to run my newly created service (MEPRequestReplyService.svc), 

Good sign, Service running perfectly, 

Now create a proxy object for the service and add it to the client application, for creating proxy you can use 'Add Service Reference' or 'svcutil'.  I'm using svcutil for all proxy generation in this sample project. 

Open visual studio command prompt and run the following svcutil command.

svcutil.exe http://localhost:5501/MEPRequestReplyService.svc?wsdl 

Once the above command is executed two files will be generated (config file and cs file), copy and paste the 'MEPRequestReplyService.cs' to the client project and also integrate the output.config file values to the client application's config file.

I have created the necessary UI and added necessary codes to call the Request-Reply service from my client (Winform),

Note: I haven't followed all best practices for implementing service client. 
private void btnSendEmail_Click(object sender, EventArgs e)
{
    ClearOutputText();
    UpdateOutputText("Start- RequestReply - SendEmail");
 
    MEPRequestReplyServiceClient client = new MEPRequestReplyServiceClient();
    client.SendEmail();
 
    UpdateOutputText("End- RequestReply - SendEmail");
}
 
private void btnGetServerTime_Click(object sender, EventArgs e)
{
    ClearOutputText();
    UpdateOutputText("Start- RequestReply - GetServerTime");
 
    MEPRequestReplyServiceClient client = new MEPRequestReplyServiceClient();
    DateTime dt = client.GetServerTime();
    UpdateOutputText(dt.ToString());
 
    UpdateOutputText("End- RequestReply - GetServerTime");
} 

Here the 'ClearOutputText()' method is used to clear the output text and 'UpdateOutputText()' is used to add text values to the output text control.  

MEPRequestReplyServiceClient client = new MEPRequestReplyServiceClient();  

The above code is used to create the service client proxy object for the 'MEPRequestReplyService'.   

client.SendEmail();   

The return type for the above method is void but still it will block the client until the service process the operation and returns an empty value.  

DateTime dt = client.GetServerTime();   

The above code will get the DateTime from the 'MEPRequestReply' service, and the final output is given below. 

One-Way

The default behavior of a service operation is Request-Reply pattern. In a Request-Reply pattern, the client waits for the reply message, even if the service operation's return type is void. With a One-Way operation, only one message is transmitted. The receiver does not send a reply message, nor does the sender expect one. No return message also means that there can be no SOAP fault returned to indicate any errors in processing or communication. (Communicating error information when operations are one-way operations requires a duplex message exchange pattern.) 

The below diagram shows how a One-Way MEP works, 

WCF One-Way Message Exchange Pattern 

One-way calls do not equate to asynchronous calls. When one-way calls reach the service, they may not be dispatched all at once and may be queued up on the service side to be dispatched one at a time, all according to the service configured concurrency mode behavior and session mode. How many messages (whether one-way or request-reply) the service is willing to queue up is a product of the configured channel and the reliability mode. If the number of queued messages has exceeded the queue's capacity, then the client will block, even when issuing a one-way call. However, once the call is queued, the client is unblocked and can continue executing while the service processes the operation in the background. This usually gives the appearance of asynchronous calls 

A One-Way operation is one in which a client invokes an operation and continues processing after WCF writes the message to the network. Operations marked with IsOneWay=true must not declare output parameters, by-reference parameters or return value otherwise you will receive an InvalidOperationException like below,

Request-Reply operation will return an HTTP status code of 200 (OK) and a full SOAP response in the message body whereas One-Way operation will only return a 202 (Accepted) status header because the request is finished as soon as the server receives the request, the below screen shot from Fiddler shows the results. 

200 Ok, 202 Accepted, Request-Reply, One-Way 

As One-way operations can't return values, any exception thrown on the service side will not make its way to the client, If transport session is used then any exception thrown by service will fault the client channel and client will not be able to use the same proxy instance. 

Below I have given a sample using One-Way MEP, 

I'm adding a new service to the service project , as 'MEPOneWayService'. Now adding a OneWay operation contract to 'IMEPOneWayService.cs' 

[ServiceContract]
public interface IMEPOneWayService
{
    #region One Way
 
    [OperationContract(IsOneWay = true)]
    void ProcessLongRunningWorks();
 
    //[OperationContract(IsOneWay = true)]  // Error due to return type other than 'void'
    //String Process(string filePath);

    #endregion
} 

Accordingly I have implemented the operation contract in ''MEPOneWayService.svc.cs' 

public class MEPOneWayService : IMEPOneWayService
{
 
    public void ProcessLongRunningWorks()
    {
        //Implement logic.
        Thread.Sleep(500);
        return;
    }
 

    //public string Process(string filePath) 
    //{
    //    throw new NotImplementedException();
    //}
} 

I have no logic implemented in 'ProcessLongRunningWorks' but for a small delay I have added Thread.Sleep. Now create proxy object for the service and add it to the client application.

Run below mentioned svcutil command in visual studio command prompt. 

svcutil.exe http://localhost:5501/MEPOneWayService.svc?wsdl 

Once its executed two files will be generated (config file and cs file), copy and paste the 'MEPOneWayService.cs' to the client project and also integrate the output.config file values to the client application's config file.

I have made the necessary codes to call the One-Way service from my client, The button click events are given below,

private void btnProcessLongRunningWorks_Click(object sender, EventArgs e)
{
    ClearOutputText();
    UpdateOutputText("Start- OneWay - ProcessLongRunningWorks");
 
    MEPOneWayServiceClient client = new MEPOneWayServiceClient();
    client.ProcessLongRunningWorks();
 
    UpdateOutputText("End- OneWay - ProcessLongRunningWorks");
} 

In the above code I have created the Proxy object for calling the one-way operation contract 'ProcessLongRunningWorks()' 

client.ProcessLongRunningWorks(); 

The client will not wait for any response from service after executing the above code as it's a One-Way MEP . The final output is given below, 

Duplex

A duplex pattern is characterized by the ability of both the service and the client to send messages to each other independently whether using one-way or request/reply messaging. 

When we use One-Way MEP in operation contract  any error occurred in service will not reach to client, in that case we can create a  one-way duplex service and return information from service to client if required, The below given diagram show how Duplex (One-Way) works. 

Below given diagram shows how a Duplex (Request-Reply) MEP works, 

In the request/reply and one-way message exchange patterns, the communication is initiated by the client application, however in the duplex message exchange pattern, both the client and the service can initiate the communication. 

The duplex pattern is slightly more complex than the request/reply or one-way patterns because of the additional mechanism for communicating with the client.To design a duplex contract, you must also design a callback contract and assign the type of that callback contract to the CallbackContract property of the ServiceContractAttribute attribute that marks your service contract.To implement a duplex pattern, you must create a second interface that contains the method declarations that are called on the client.  

For demonstrating Duplex message exchange pattern, I have added a new service 'MEPDuplexService' to service project and modified the interface as below. 

// Define a duplex service contract.
// A duplex contract consists of two interfaces.
// The primary interface is used to send messages from client to service.
// The callback interface is used to send messages from service back to client.
// IMEPDuplexService allows one to perform multiple operations on a running result.
// The result is sent back after each operation on the IMEPDuplexServiceCallback interface.    
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IMEPDuplexService" in both code and config file together.
[ServiceContract(CallbackContract = typeof(IMEPDuplexServiceCallback))]
public interface IMEPDuplexService
{
    #region Duplex
 
    [OperationContract(IsOneWay = true)]
    void SendBulkEmails();
 
    [OperationContract] //Default (IsOneWay = false) means Request-Reply.
    string[] UploadFile();
 
    #endregion
} 

In above code I have mentioned the call back contract as CallbackContract = typeof(IMEPDuplexServiceCallback) and one operation contract is mentioned as OneWay and other as RequestReply.   

CallBack interface 'IMEPDuplexServiceCallback' is defined as below,  

// The callback interface is used to send messages from service back to client.
// The Progress operation will return the creal time status.
public interface IMEPDuplexServiceCallback
{
    #region Duplex Callback
 
    [OperationContract(IsOneWay = true)]
    void Progress(string status);
 
    #endregion
} 

Operation Contract will be calling the 'Progress' method from the 'IMEPDuplexServiceCallback' for callback purpose. 

Accordingly I have implemented the definition for the operation contract in wcf service as below,  

// Service class which implements a duplex service contract.
// Use an InstanceContextMode of PerSession to store the result
// An instance of the service will be bound to each duplex session    
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "MEPDuplexService" in code, svc and config file together.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class MEPDuplexService : IMEPDuplexService
{
    public void SendBulkEmails()
    {
        int count = 10;
        for (int i = 1; i < count + 1; i++)
        {
            Thread.Sleep(50);
            //Implement logic
            OperationContext.Current.GetCallbackChannel<IMEPDuplexServiceCallback>().Progress(i.ToString() + "/" + count.ToString() + " - sent");
        }
        return;
    }
 
    public string[] UploadFile()
    {
        string[] Status = new string[2];
        int count = 15;
        for (int i = 1; i < count + 1; i++)
        {
            Thread.Sleep(50);
            //Implement logic
            OperationContext.Current.GetCallbackChannel<IMEPDuplexServiceCallback>().Progress(i.ToString() + "/" + count.ToString() + " - uploaded");
        }
        Status[0] = "Success";
        Status[1] = "Uploaded " + count.ToString() + "/" + count.ToString();
        return Status;
    }
} 

I have used "InstanceContextMode = InstanceContextMode.PerSession" so that the instance of the service will be bound to each duplex session, 

When ConcurrencyMode configured to Reentrant ("ConcurrencyMode = ConcurrencyMode.Reentrant"), the service instance is still associated with a lock, and only a single-threaded access is allowed. However, if the service is calling back to its clients, Windows Communication Foundation will silently release the lock first. So by using Reentrant results in no deadlock. 

In the above code the callback is done using below mentioned code. 

OperationContext.Current.GetCallbackChannel<IMEPDuplexServiceCallback>().Progress(i.ToString() + "/" + count.ToString()); 

Now just run to see the Duplex Service in action.

Oops...

As we have created duplex message exchange pattern we need to define the duplex contract too config file. I have added the below contract to service project's web.config file. I have specified the binding as 'wsDualHttpBinding' for duplex contract 

<services>
  <service name="MEP.Services.MEPDuplexService">
    <endpoint address ="" binding="wsDualHttpBinding" contract="MEP.Services.IMEPDuplexService">
    </endpoint>
</service> 

Now create proxy object for the service and add it to the client application, execute the below command in visual studio command prompt..

svcutil.exe http://localhost:5501/MEPDuplexService.svc?wsdl 

Once its executed two files will be generated (config file and cs file), copy and paste the 'MEPDuplexService.cs' to the client project and also integrate the output.config file values to the client applications config file.

Now we have done everything for Duplex from the service side, so we need to implement the duplex call back method in client for the callback purpose.  The below code will be called for every call back in client side. 

[CallbackBehavior(UseSynchronizationContext = false)]
public class DuplexService_CalBack : IMEPDuplexServiceCallback
{
    public void Progress(string status)
    {
        UpdateOutputText(status);
    }
} 

Duplex (OneWay) is coded as given below , 

private void btnSendBulkEmails_Click(object sender, EventArgs e)
{
    ClearOutputText();
    UpdateOutputText("Start- Duplex - SendBulkEmails (OneWay)");
 
    InstanceContext instanceContext = new InstanceContext(new DuplexService_CalBack());
 
    MEPDuplexServiceClient client = new MEPDuplexServiceClient(instanceContext);
 
    client.SendBulkEmails();
 
    UpdateOutputText("End- Duplex - SendBulkEmails (OneWay)");
} 

The callback class 'DuplexService_CalBack()' is passed in the InstanceContext and the instanceContext is passed in the service proxy object creation. When we click on the button we will get the output as below, 

If you see the output the "End" message is shown just after the "Start", that means that the client is not waiting for the response from the service and callback is coming after executing other statements. 

private void btnUploadFile_Click(object sender, EventArgs e)
{
    ClearOutputText();
    UpdateOutputText("Start- Duplex - UploadFile (RequestReply)");
 
    InstanceContext instanceContext = new InstanceContext(new DuplexService_CalBack());
 
    MEPDuplexServiceClient client = new MEPDuplexServiceClient(instanceContext);
 
    string[] result = client.UploadFile();
 
    UpdateOutputText("--Output from Service--" + Environment.NewLine
                        + result[0] + Environment.NewLine
                        + result[1]);
 
    UpdateOutputText("End- Duplex - UploadFile (RequestReply)");
}  

The 'UploadFile' operation contract is a request-reply pattern and the return value is coming as a string[], the client is waiting for the reply and the callbacks are coming in between request and reply. you will get more understanding when you look at the output below. 

 

Using Attached Code

I have attached the working code with this article, Just download the .zip file and extract then open the solution file,

Solution file will load two projects in Visual Studio IDE. The WCF_MEP solution screen shot is given below, 

Now browse the .svc file from services project, When I browsed my URL was starting with 'http://localhost:5501/'

If your URL is different for the service then update the same in App.config of WINFRM project

<bindings>
  <wsDualHttpBinding>
    <binding name="WSDualHttpBinding_IMEPDuplexService" />
  </wsDualHttpBinding>
  <basicHttpBinding>
    <binding name="BasicHttpBinding_IMEPRequestReplyService" />
    <binding name="BasicHttpBinding_IMEPOneWayService" />
  </basicHttpBinding>
</bindings>
<client>
  <endpoint address="http://localhost:5501/MEPDuplexService.svc"
      binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IMEPDuplexService"
      contract="IMEPDuplexService" name="WSDualHttpBinding_IMEPDuplexService">
  </endpoint>
 
  <endpoint address="http://localhost:5501/MEPRequestReplyService.svc"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMEPRequestReplyService"
            contract="IMEPRequestReplyService" name="BasicHttpBinding_IMEPRequestReplyService" />
 
  <endpoint address="http://localhost:5501/MEPOneWayService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMEPOneWayService"
        contract="IMEPOneWayService" name="BasicHttpBinding_IMEPOneWayService" />
      
</client> 

After doing above things you can run and play with the downloaded WCF_MEP project.

References 

Summary

In this article I have explained WCF - Message Exchange Patterns with a sample Winform application. I hope you have enjoyed this article and got some value addition to your knowledge.

I have put my time and efforts on all of my articlesPlease don't forget to mark your votessuggestions and feedback to improve the quality of this and upcoming articles. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Shemeer NS
Software Developer (Senior)
India India
Technology Specialist | CodeProject MVP | Visual Studio Gallery Contributor | Author | Geek | Netizen | Husband | ChessPlayer
 
Most of my articles are listed on top 5 of the respective 'Best articles of the month' and some of my articles are published on ASP.NET WebSite's Article of the Day section.
 
Check my contributions in Visual Studio Gallery and Code Project
 
Technical Blog: http://www.shemeerns.com
Facebook: http://facebook.com/shemeernsblog
Twitter : http://twitter.com/shemeerns
Google+ : http://google.com/+Shemeernsblog
Follow on   Twitter   Google+

Comments and Discussions

 
GeneralMy vote of 5 Pinmembermirfan0011-Jun-13 21:07 
GeneralMy vote of 5 PinmemberRoman G2-Apr-13 22:42 
GeneralRe: My vote of 5 PinmvpShemeer NS21-Apr-13 19:36 
GeneralMy vote of 5 PinmemberL Hills2-Apr-13 1:41 
I specially like the animated demos
GeneralRe: My vote of 5 PinmvpShemeer NS21-Apr-13 19:36 
GeneralMy vote of 5 PinmemberAbhishek Ranjan Srivastava1-Apr-13 20:21 
GeneralRe: My vote of 5 PinmvpShemeer NS21-Apr-13 19:35 
GeneralMy vote of 5 PinmemberTechnoGeek00131-Mar-13 18:22 
GeneralRe: My vote of 5 PinmvpShemeer NS21-Apr-13 19:34 
GeneralMy vote of 5 PinmemberPrasad Khandekar31-Mar-13 5:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140421.2 | Last Updated 31 Mar 2013
Article Copyright 2013 by Shemeer NS
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid