AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=1335&pId=-1
Asynchronous Pattern in Windows Communication Foundation
page
by Keyvan Nayyeri
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 74969/ 94

Introduction

Asynchronous pattern is a very well known and common design pattern in systems that are built on top of executions.  You are probably familiar with some of asynchronous pattern implementations in different aspects of technology.  In software and electronic systems, asynchronous pattern have been widely used.

Like many other technologies, this pattern has an implementation in Windows Communication Foundation which is the topic of this article.

In this article first I will describe an asynchronous pattern in general and how it is supported by Microsoft in .NET Framework then will talk about its definition in WCF.  After giving this basic information, I will talk about details of its configurations as well as its implementation in service and client sides of a WCF application by discovering an example.

Asynchronous Pattern in a Nutshell

Before implementing our asynchronous pattern in WCF, I think it is better to give an introduction to asynchronous pattern and its applications in this section.  Many of you may be partially or completely familiar with this design pattern so you can escape this section and read the next sections directly.

For long running executions in an application, there is a probability that a current thread cannot keep executing because it may stop user interface.  For example, when a Windows application goes to a new state to execute a long running process, windows may freeze and even crash.  One solution is to move this execution to another thread and let it follow there.

Asynchronous pattern comes into play to solve this issue and Microsoft has a built-in mechanism for this pattern in its great .NET Framework.  Microsoft's implementation of this pattern consists of these pieces:

·         Two methods for an asynchronous operation

·         An object which implements IAsyncCallback interface

·         A callback delegate

This way, execution of a method splits into two steps.  In the first step you create the background process and start it and in the second step you listen for changes in process and wait until it finishes.

For example, if we have a method to add two numbers and name it Add() then asynchronous version of this method consists of two methods: BeginAdd() and EndAdd().

If Add() has a signature like this:

int Add(int x, int y);

Then BeginAdd() has this signature:

IAsyncResult BegingAdd(int x, int y, AsyncCallback callback, object state);

As you see, BeginAdd() has two extra parameters in comparison with original Add() method:

·         AsyncCallback: A delegate that gets an IAsyncResult parameter and does not return anything.  It will be called when asynchronous operation is completed.

·         object: It keeps the state of the asynchronous  operation as an IAsyncResult object.

This method also returns an IAsyncResult object rather than the original integer type.

On the other hand, EndAdd() has the following signature:

int EndAdd(IAsyncResult ar);

As you see, this method only has one parameter of IAsyncResult type. This object gives all necessary information about the state of operation and has the following properties.

·         AsynState: Gets an object that provides some information about asynchronous operation.

·         AsycWaitHandler: Gets a WaitHandle to wait for an asynchronous operation to complete.

·         CompletedSynchronously: Indicates if the asynchronous operation has completed synchronously.

·         IsCompleted: Indicates if the asynchronous operation has completed.

Having this background information, we can step into WCF and talk about asynchronous pattern implementation in it which may be a little different than what you have seen in other parts of .NET Framework.

Configuration

There is nothing special for asynchronous pattern implementation on configuration side for services or clients because nothing changes for message formats and other intermediary stuff when you use asynchronous pattern.

Service can implement its methods synchronously, but client can get access to them asynchronously.  In the opposite direction, clients can implement some methods synchronously but the service can implement them asynchronously.

Service

Asynchronous pattern can be implemented on the service side by creating operation contracts for asynchronous implementation.  To do this, you can add an OperationContract attribute to your operations and set its AsyncPattern to true.  Apparently there are two operations in service contract to implement asynchronous pattern as described above, but you add this attribute to Begin method only even though both Begin and End methods will be implemented.  .NET will take care of this method internally (as you will see later).

In this article I use a simple example to implement asynchronous version of a method that gets two integer values and returns the result of add operation on them.

If I want to implement asynchronous pattern for an Add() service method which normally has a service contract like Listing 1 and a service class implementation like Listing 2 then I have to implement this operation in some steps as what you see in this section.

Listing 1: Normal Service Contract

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
 
namespace AsyncWCF
{
    [ServiceContract()]
    public interface IAddService
    {
        [OperationContract]
        int Add(int number1, int number2);
    }
}

Listing 2: Normal Service Implementation

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.Threading;
 
namespace AsyncWCF
{
    public class AddService : IAddService
    {
        #region IAddService Members
 
        public int Add(int number1, int number2)
        {
            return (number1 + number2);
        }
 
        #endregion
    }
}

Let me begin implementing this method with the asynchronous pattern.

First step is to create a service contract.  As I stated above, I have to include two methods for my Add() method in asynchronous version: BeginAdd() and EndAdd() and first method should be marked with an OperationContract attribute with AsyncPattern property set to true (Listing 3).

Listing 3: Service Contract

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
 
namespace AsyncWCF
{
    [ServiceContract()]
    public interface IAddService
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginAdd(int number1, int number2, 
            AsyncCallback callback, object state);
 
        int EndAdd(IAsyncResult ar);
    }
}

At this point, I should implement IAsyncResult to use it in my code.  It is common to implement this interface in a class in the general form then derive a class with this newly created base class based on project requirements.  So, first I create an AsyncResult base class and implement IAsyncResult for it.  I also implement IDisposable to manage my resources better.  This implementation does not have anything related to my project.  It just implements a logic that can be used in other projects as well. The final code for the AsyncResult class is shown in Listing 4.

Listing 4: AsyncResult Class

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
 
namespace AsyncWCF
{
    public class AsyncResult : IAsyncResult, IDisposable
    {
        AsyncCallback callback;
        object state;
        ManualResetEvent manualResentEvent;
 
        public AsyncResult(AsyncCallback callback, object state)
        {
            this.callback = callback;
            this.state = state;
            this.manualResentEvent = new ManualResetEvent(false);
        }
 
        object IAsyncResult.AsyncState
        {
            get { return state; }
        }
 
        public ManualResetEvent AsyncWait
        {
            get
            {
                return manualResentEvent;
            }
        }
 
        WaitHandle IAsyncResult.AsyncWaitHandle
        {
            get { return this.AsyncWait; }
        }
 
        bool IAsyncResult.CompletedSynchronously
        {
            get { return false; }
        }
 
        bool IAsyncResult.IsCompleted
        {
            get { return manualResentEvent.WaitOne(0, false); }
        }
 
        public void Complete()
        {
            manualResentEvent.Set();
            if (callback != null)
                callback(this);
        }
 
        public void Dispose()
        {
            manualResentEvent.Close();
            manualResentEvent = null;
            state = null;
            callback = null;
        }
    }
}

Let me describe some points about the above code.  AsyncResult has some properties, like AsyncCallback, state object and a ManualResetEvent, which handle waiting for asynchronous operation.  There is an IsCompleted property which returns a Boolean value to specify that if the operation is completed asynchronously, a simple WaitOne(0, false) method call always returns the appropriate value for any asynchronous operation.

The last point is about Complete() method.  Here I call the Set() method of my ManualResetEvent to show that my event is signaled and any other awaiting thread can follow. Then I pass the current object to callback if callback is not null.

After this, I create an AddAsyncResult class and inherit it from AsyncResult to add a few properties for my requirements and use them later.  It just keeps a few values as the first and second numbers and the result of performing add operation on them (Listing 5).

Listing 5: AddAsyncResult Class

using System;
using System.Collections.Generic;
using System.Text;
 
namespace AsyncWCF
{
    internal class AddAsyncResult : AsyncResult
    {
        public readonly int number1 = 0;
        public readonly int number2 = 0;
 
        private int result;
 
        public int Result
        {
            get { return result; }
            set { result = value; }
        }
 
        public AddAsyncResult(int num1, int num2, 
            AsyncCallback callback, object state)
            : base(callback, state)
        {
            this.number1 = num1;
            this.number2 = num2;
        }
    }
}

Alright, now I have created what I needed to begin implementing my service logic.  Here I write my code logic for the service.

In the BeginAdd() method I create an instance of AddAsyncResult by passing appropriate parameters to it then call ThreadPool.QueueUserWorkItem() method to add a method to waiting queue for execution.  This method will run whenever a thread becomes available.  The logic for my CallbackMethod will be discussed later.  BeginAdd() returns my AddAsyncResult object as the result.  Listing 6 shows the code of BeginAdd() method.

Listing 6: BeginAdd() Method

public IAsyncResult BeginAdd(int number1, int number2,
    AsyncCallback callback, object state)
{
    AddAsyncResult asyncResult =
        new AddAsyncResult(number1, number2, callback, state);
 
    ThreadPool.QueueUserWorkItem(new WaitCallback
        (Callback), asyncResult);
 
    return asyncResult;
}

In the Callback(), which is presented in Listing 7, I simply convert the passed object to an AddAsyncResult and try to set its Result property to the returned value of InternalAdd() operation (will be shown in a moment).  At the end, I call the Complete() method to release the thread and allow the other operations to execute.

Listing 7: Callback() Method

private void Callback(object state)
{
    AddAsyncResult asyncResult = state as AddAsyncResult;
    try
    {
        asyncResult.Result = InternalAdd(asyncResult.number1,
            asyncResult.number2);
    }
    finally
    {
       asyncResult.Complete();
    }
}

Logic of InternalAdd() is very very simple and what you can expect from an Add operation.  But it also puts a short delay (15 seconds) before adding numbers to make the execution longer (Listing 8).

Listing 8: InternalAdd() Method

private int InternalAdd(int number1, int number2)
{
    Thread.Sleep(15000);
    return number1 + number2;
}

And finally, there is the EndAdd() method (Listing 9).  Here I convert passed IAsyncResult parameter to an AddAsyncResult object and call the WaitOne() method of its ManualResetEvent to wait until the current execution ends then return the Result property.

Listing 9: EndAdd() Method

public int EndAdd(IAsyncResult ar)
{
    int result = 0;
 
    if (ar != null)
    {
        using (AddAsyncResult asyncResult = ar as AddAsyncResult)
        {
            if (asyncResult == null)
                throw new ArgumentNullException(
                    "IAsyncResult parameter is null.");
 
            asyncResult.AsyncWait.WaitOne();
 
            result = asyncResult.Result;
        }
    }
    return result;
}

So far so good!  I have written my service completely.  Now I deploy this service to IIS and host it there in order to use SvcUtil command to generate a proxy class and configuration file for my client.  For more information about hosting WCF services you can read my article entitled Start Development with Windows Communication Foundation.

Client

My implementation is almost done because there is nothing special on the client side. You create a proxy and call the Add() method to calculate the result (Listing 10).  Notice the name of the Add() method.  There was no service method with this name, but WCF generated this name of my method and there is no BeginAdd() or EndAdd() method available for client. Therefore, clients cannot know if a method is implemented normally or asynchronously.

Listing 10: Client Code

using System;
using System.Collections.Generic;
using System.Text;
 
namespace AsyncWCFClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = 
                "Asynchronous Pattern in Windows Communication Foundation";
 
            Console.WriteLine("Enter Number 1:");
            int number1 = Convert.ToInt32(Console.ReadLine());
 
            Console.WriteLine("Enter Number 2:");
            int number2 = Convert.ToInt32(Console.ReadLine());
 
            using (AddServiceClient proxy = new AddServiceClient())
            {
                Console.WriteLine("Wait until operation ends asynchronously ...");
                int result = proxy.Add(number1, number2);
                Console.WriteLine("Result = {0}", result.ToString());
            }
            Console.ReadLine();
        }
    }
}

The output of this console application can be seen in Figure 1.

Figure 1: The Output

Downloads

[Download Sample]

Source codes for service and client that I described as a case study in this article are available here.

Summary

In this article you learned about asynchronous pattern in Windows Communication Foundation in .NET 3.0 and how to implement this famous pattern in your service and client to enable long running executions in your WCF applications.  You also saw an example of this implementation in action.



©Copyright 1998-2021 ASPAlliance.com  |  Page Processed at 2021-12-08 2:22:25 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search