Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Tutorial on Message Exchange Patterns and Asynchronous Operations in WCF

4.96/5 (15 votes)
31 Mar 2013CPOL10 min read 53K   1.1K  
This article discusses the various message exchange patterns that the WCF service supports and how to call WCF operations asynchronously

Introduction

In this article we will discuss the various message exchange patterns that the WCF service supports. We will also discuss how we can invoke the WCF service functions asynchronously. We will try to see each one of these message exchange techniques in details and try to see a sample application for each one of them.

Background 

Calling a function from the application code always follows a simple Request-Response pattern i.e. we call the function, for the time the function is being executed the caller will wait for the function(block) and once the function call returns the calling code with become responsive again.

Now this simple request-response is ok for the functions that takes very little time to execute. But if the function being called takes some considerable time to execute then the calling code will be unresponsive for that period. This will pose serious problems for the applications that require user interactions.

In case of simple libraries, we can invoke the functions asynchronously and let our application be responsive and then handle the response from the function separately. From a WCF service perspective, this async function call model is also allowed but WCF also provides some message exchange patterns out of the box to provide these kind of functionality.

Before looking at the message exchange pattern let us think about the scenarios that we might need from a service consumers perspective.

  1. Scenario 1: We have some function calls that are not taking too much time and letting the application wait for such functions is totally acceptable.
  2. Scenario 2: We have some function call which is time consuming but calling that function is more like a trigger from our application code. We just want to call the function and don't want to wait for the response from the function.
  3. Scenario 3: We have a long running function, we want to call the function in such a way that the function call is not blocking and at the same time we want something out of the function(response) into our application.
  4. Scenario 4: We want a two way communication mechanism(like events) where we hook up our client with the service, call a function and return back. The service can in turn call a callback function to let the application know about the response.

Now WCF provides the possibility of configuring our service and service proxy in such a way that all these scenarios are possible to implement. From the Message Exchange Patterns perspective, WCF provides support for 1st, 2nd and 4th scenario. To have the 3rd scenario working we need to implement the async function calls at the client side proxy.

Message Exchange Patterns

WCF provides 3 message exchange patterns:

  1. Request/Response
  2. One Way
  3. Duplex

The Request/Reponse pattern is the default and is most widely used pattern. In this pattern the application waits/blocks till the service function call is complete(Scenario 1). Default OperationContract behavior is Request/Response only but if we need to specify it explicitly then we have to configure the IsOneWay property of OperationContract to false.

One way specifies that the function call will not be blocking. The client will simply call the function and the control will return to the caller(Scenario 2). To make a function One way complaint we will have to set the IsOneWay property of OperationContract to true.

Duplex provides us with the possibility of having a callback function/object hooked up with the service(Scenario 4). This will require having an extra interface that the client will need to implement. If together with this callback interface, we mark the function call as IsOneWay=true then the function call will be non blocking and the WCF service will send the callback to the client once the operation is complete. This pattern is also important when the client wishes to receive some state change information from the service even when it has not called any operation on the service(More like publisher subscriber model).

Now in some way we can say that the Scenario 3 problem can also be addressed using the Duplex service. But having a duplex service has some limitations and it is not exactly calling the operations asynchronously. To solve the Scenario 3 problem, we can call the long running function asynchronously(we will look into it shortly).

Using the code

Let us now create a simple WCF service that will expose 3 functions. One function to be called in Request/Reponse mode i.e. with IsOneWay=false. Second function to be called using One-Way pattern i.e. setting the IsOneWay=true. And finally a third function that will call the callback on the client side to notify that the call is complete.

Now since we need to demonstrate the Duplex service behavior too, let us create a duplex service only. The first two functions will work in the same fashion in a non duplex service too. Only the third function will utilize the duplex service benefits. Now the steps to create a duplex service are:

  1. Create the service contract: We will create a simple service contract ISampleService.
  2. Create a callback contract: We will create a simple interface called ICallBack as callback contract.
  3. Attach callback contract with service contract: we do this by specifying property  CallbackContract=typeof(ICallBack) in the service contract. 
  4. Expose the service: using  wsDualHttpBinding. 
  5. Implement the callback contract: We will create a simple class called CallbackHandler and implement the callback contract interface(code can be found below).
  6. Create an InstanceContext and pass the callback contract instance: This is also done on client side(code can be found below).
  7. Pass the InstanceContext object in the proxy class' constructor: This is also done in client code(code can be found below).
Let us now see the implementation of this duplex service and then we will see the client implementation to consume this duplex service.  

C#
[ServiceContract(CallbackContract=typeof(ICallBack))] 
public interface ISampleService
{
    // Request-Response Mode
    [OperationContract]
    void TestFunction1();

    // One Way mode
    [OperationContract(IsOneWay=true)]
    void TestFunction2();

    // Duplex service mode
    [OperationContract(IsOneWay = true)]
    void TestFunction3();
}

[ServiceContract] // Callback interface to be implemented by client
public interface ICallBack
{
    [OperationContract(IsOneWay=true)]
    void NotifyClient(string message);
}

The above code snippet shows the service contract and operation contract. Now this service is a Duplex service and for that we have configured the CallBackContract property of service contract to point to the callback interface that we have defined.

Note: TestFunction1 and TestFunction2 will not utilize the Duplex service behaviors. They will work in the same way even if the service is not a Duplex service. So we can test the other two modes without any problem.

Now the implementation of these functions will simulate some long running process. We do this by sleeping for 5 seconds.

C#
public class SampleService : ISampleService
{
    public void TestFunction1()
    {
        // Let us simulate some time consuming function
        Thread.Sleep(5000);
    }

    public void TestFunction2()
    {
        // Let us simulate some time consuming function
        Thread.Sleep(5000);
    }

    public void TestFunction3()
    {
        // Let us simulate some time consuming function
        Thread.Sleep(5000);

        ICallBack callBack = OperationContext.Current.GetCallbackChannel<ICallBack>();
        callBack.NotifyClient("TestFunction3 has been successfully executed");
    }
}

This service will now be exposed using the wsDualHttpBinding binding because this is the binding that will support duplex mode of communication.

Test Service Client

Let us create a simple windows application so that we can see whether or not the GUI is responsive on making function calls. This will be a simple application which will have separate buttons to invoke each function. The response from the function will be shown on the UI.

Image 1

We will add the service reference into this client application and will test each function call one by one.

Request/Response

The TestFunction1 is configure in request-response mode i.e. IsOneWay is set to false(the default). The code to call this function using the client proxy is:

C#
InstanceContext instance = new InstanceContext(new CallbackHandler());
ServiceReference1.SampleServiceClient client = new ServiceReference1.SampleServiceClient(instance);

listBox1.Items.Add("Request/Response: Calling the WCF service function.");
client.TestFunction1();
listBox1.Items.Add("Request/Response: WCF service function call complete.");
client.Close();

Calling this function from the client will make the UI to hang for 5 seconds because the calling code is waiting for the function call to finish.

Image 2

One Way

The TestFunction2 is configure in One way mode i.e. IsOneWay is set to true. The code to call this function using the client proxy is:

C#
InstanceContext instance = new InstanceContext(new CallbackHandler());
ServiceReference1.SampleServiceClient client = new ServiceReference1.SampleServiceClient(instance);

listBox1.Items.Add("One way: Calling the WCF service function.");
client.TestFunction2();
listBox1.Items.Add("One way: WCF service function call complete.");
client.Close();

Calling this function from the client will not make the UI non responsive because the calling code is not waiting for the function call to finish. It simply calls the function and returns back assuming that the function will do its bit.

Image 3

Note: The InstanceContext mode is needed because we created a Duplex service. If we would have not created a duplex service then it was not required and the parameter-less constructor of SampleServiceClient would have been called instead. In case of non duplex services only this change will be required and the code will work fine.

Duplex

Now to have the possibility of receiving the callbacks from the service, we first need to implement the callback interface of the service.

C#
// Internal class that implements the callback interface
class CallbackHandler : ServiceReference1.ISampleServiceCallback
{
    public void NotifyClient(string message)
    {
        MessageBox.Show(message);
    }
}

This callback class' instance will be passed inside the InstanceContext and this InstanceContext will be passed to the service so that the service can establish a connection with the client and call the callback functions. Calling the function is same but we need to make the SampleServiceClient a class level member variable so that the instance is alive when the service sends the callback.

C#
InstanceContext instance = null;
ServiceReference1.SampleServiceClient client = null;

public Form1()
{
    InitializeComponent();

    instance = new InstanceContext(new CallbackHandler());
    client = new ServiceReference1.SampleServiceClient(instance);
}

private void button3_Click(object sender, EventArgs e)
{
    listBox1.Items.Add("Duplex: Calling the WCF service function.");
    client.TestFunction3();
    listBox1.Items.Add("Duplex: WCF service function call complete.");
}

Now calling this function will not block the UI because this function is also marked as IsOneWay=true. But since the function implementation calls the callback function of the client the function implementation NotifyClient will be called once the function call is complete(after 5 seconds) and will show us the message box. 

Image 4

Calling the Operations Asynchronously

Now if we have a long running process which is neither marked as one way operation nor it is possible to have a duplex service, then the only option from the clients perspective is to call this method asynchronously. Calling the methods asynchronously gives us the possibility of having responsive caller code with the proper response message being also getting captured in the client.

The first thing that we need to do to implement asynchronous method call is to configure the proxy to generate the support for async functions.

Image 5

Now this gives us the async version of all the functions along with the callback events that will be called when the function call is finished. So let us call the Function1 again but this time asynchronously

C#
InstanceContext instance = new InstanceContext(new CallbackHandler());
ServiceReference1.SampleServiceClient client = new ServiceReference1.SampleServiceClient(instance);

listBox1.Items.Add("Request/Response: Calling the WCF service function async");
client.TestFunction1Completed += new EventHandler<AsyncCompletedEventArgs>(client_TestFunction1Completed);
client.TestFunction1Async();
listBox1.Items.Add("Request/Response: WCF service function async call complete.");
client.Close();

Upon completion the event handler will be called and show us the message box indicating that the function call has been complete.

Image 6

Note: This is the client side implementation of async pattern where the client application call the operation in a separate thread and manages the communication with main thread. We can also create async operations on WCF service where a separate thread is created inside the service itself. This is done by setting the AsyncPattern property of OperationContract to true. But this itself is considerable topic and perhaps need a separate discussion altogether. Talking about it in this article will make this article little digressing. 

Some important points

The request response pattern is the most common and widely used pattern. If we are using some other pattern then there are some limitations that comes with them. Let us see these limitations before deciding upon the pattern to use in our WCF service.

One Way: When we use One way pattern once the function is called there is no link between the caller and the callee. This is ok because we needed this behavior. But the catch here is that the caller has no way of knowing whether the function call was success or failure. We cannot propagate any faults back to the client because the link between client and the service will no longer exist when the function execution is in progress.

Duplex: Duplex service works on some limited bindings. Not all the bindings support duplex communication. Duplex services need to have a connection between the client and the server. This is not always possible due to network design limitations. The Duplex service can also rise some subtle threading relation issues which might be hard to fix or perhaps cause some unexpected behavior.

Point of interest

In this article, we have seen all the three possible message exchange patterns supported by the WCF service and how we can call the operations asynchronously from the client. The code snippets shown in this article are only showing the bare minimum code needed in the context. To get the full understanding looking at the sample application is recommended. I hope this has been informative.

History

  • 30 March 2013: First version.

License

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