Asynchronous Pattern in Windows Communication Foundation
page 4 of 7
by Keyvan Nayyeri
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 53706/ 46

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.


View Entire Article

User Comments

Title: 2012 NFL jerseys   
Name: NIKE NFL jerseys
Date: 2012-05-20 11:27:08 PM
Comment:
[/pre]Cheap NFL,NBA,MLB,NHL
[url=http://www.jersey2shop.com/]Jerseys From China[/url]
[url=http://www.jersey2shop.com/]2012 nike nfl Jerseys[/url]
[url=http://www.jersey2shop.com/]cheap China Jerseys[/url]
[url=http://www.jersey2shop.com/]Sports Jerseys China[/url]
[url=http://www.jersey2shop.com/NFL-Jerseys-c68/]NFL Jerseys China[/url]
[url=http://www.jersey2shop.com/NBA-Jerseys-c77/]NBA Jerseys China[/url]
NHL Jerseys China
[url=http://www.jersey2shop.com/MLB-Jerseys-c94/]MLB Jerseys China[/url]NFL jerseys For Sale online.All Our Jerseys Are Sewn On and Directly From Chinese Jerseys Factory
[/pre]
[pre]We Are Professional China jerseys Wholesaler
[url=http://www.cheapjersey2store.com/]Wholesale cheap jerseys[/url]Cheap mlb jerseys
[url= http://www.cheapjersey2store.com/]2012 mlb all atar jerseys[/url]
[url= http://www.cheapjersey2store.com/ [/url]Cheap China Wholesael[/url]
[url= http://www.cheapjersey2store.com/]Wholesale jerseys From China[/url]
[url=http://www.cheapjersey2store.com/]2012 nike nfl Jerseys[/url]Free Shipping,Cheap Price,7 Days Deliver
[/pre]
[/pre]
We are professional jerseys manufacturer from china,wholesal
sports [url= http://www.cheapjersey2store.com/]Jerseys From China[/url]
[url=http://www.cheapjersey2store.com/NFL-Jerseys-c68]NFL jerseys China[/url]
[url=http://www.cheapjersey2store.com/NHL-Jerseys-c96/]NHL Jerseys China[/url]
[url=http://www.cheapjersey2store.com/NBA-Jerseys-c77/]NBA Jerseys China[/url]
[url=http://www.cheapjersey2store.com/MLB-Jerseys-c94/]MLB Jerseys China[/url]
[url= http://www.cheapjersey2store.com/]China Jerseys[/url],Free Shipping
[/pre]
[/pre]
We are professional jerseys manufacturer from china,wholesal
sports [url= http://www.jerseycaptain.com/]cheap jerseys sale online [/url]
[url= http://www.jerseycaptain.com/]2012 nike nfl Jerseys[/url]
[url=http://www.jerseycaptain.com/NFL-Jerseys-c68]cheap NFL jerseys China[/url]
[url=http://www.jerseycaptain.com/NHL-Jerseys-c96/]NHL Jerseys C
Title: Thanks !   
Name: shibu
Date: 2011-01-18 2:34:06 AM
Comment:
is there any vb.net version
Title: thanks!   
Name: dulcissa
Date: 2010-12-09 3:54:17 PM
Comment:
thank you! very useful!
Title: Very very useful......   
Name: Devender Yadav
Date: 2010-10-29 11:16:13 PM
Comment:
Thanks for this articles
Title: Is this joke?   
Name: Jigga
Date: 2010-07-23 1:19:04 PM
Comment:
Where are You using it asynchronously? Yor client code makes no sense.
Title: Very Helpful   
Name: Ted
Date: 2010-07-07 12:05:06 PM
Comment:
Very instructive and useful
Title: Where's the Client?   
Name: Adam
Date: 2009-06-02 4:09:23 PM
Comment:
There is no call in the client side that makes use of the callback routine to discover when the operation is complete. It looks like you did a ton of work to create an asynchronous way to call the Add function, and then the client totally skips it and calls it synchrously. Am I missing something?
Title: Thanx   
Name: MC
Date: 2008-02-21 4:02:44 PM
Comment:
Very hepful !
Title: Event-Based Asynchronous Programming   
Name: Nirmala
Date: 2007-11-23 7:47:55 AM
Comment:
Why Event-Based Asynchronous Programming is not supported in WCF proxy? Is there any work around to fill the gap?
Title: InvokeAsync in WCF   
Name: Nirmala
Date: 2007-11-23 7:33:17 AM
Comment:
In WebService proxy, we have InvokeAsync (of SoapHttpClientProtocol).
But, WCF proxy is missing the InvokeAsync.

Will VS 2008/3.5 support InvokeAsync?
Title: Asynchronous Pattern in WCF   
Name: Nirmala Patthi
Date: 2007-11-19 6:02:17 AM
Comment:
Hi Keyvan Nayyeri,

Thanks for your article. Do you have any idea how to implement Async2 patten in WCF? In the dotnet WebServices, SoapHttpClientProtocol has InvokeAsync that implements Async2 pattern (that is newly introduced in asp.net 2.0 framework).
When we create a WebService proxy, it will have the InvokeAsync implemented by default.
However, when we create a WCF proxy, InvokeAsync is not generated, rather we will have BeginInvoke, EndInvoke though.
I am not sure about if dotnet 3.5 framework, if WCF will come with Async2 pattern.
Can you please comment on this?
Title: Thanks   
Name: Keyvan Nayyeri
Date: 2007-07-13 3:19:21 AM
Comment:
Thank you Darren :-)
Title: Nice!   
Name: Darren Neimke
Date: 2007-07-13 3:04:25 AM
Comment:
Nice stuff Keyvan... thanks for sharing :-)






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-19 4:09:25 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search