Rashim's Blog

IAsyncResult asynchronous operation in WCF

Posted on: February 8, 2014

We are very well-versed that WCF service operations can be implemented asynchronously or synchronously .And the clients can call service operations synchronously or asynchronously since asynchronous service operations can be calling synchronously and vice versa. There are three ways to implement asynchronous operations

As a series of sequence, in this post, I am going to use IAsyncResult asynchronous operation but we should keep in mind that this pattern is no longer recommended for further development. If we know these three mechanisms of asynchronous operation it would be easier for us to architect our large distributed system based on asynchronous service. Before going to our implementation I would recommend you to have a look on APM Model first. I would like to Organize todays article in three steps; Service Implementation, Service Hosting and Client

Service Implementation

In IAsyncResult asynchronous system asynchronous operations require Begin and End methods.


[ServiceContract]
 public interface IMessageService
 {
 [OperationContract(AsyncPattern = true)]
 IAsyncResult BeginGetMessage(string message, AsyncCallback callback, object state);

string EndGetMessage(IAsyncResult asyncResult);
 }

In the service contract, I declare an asynchronous method pair according to the APM. The BeginGetMessage method takes a parameter, a callback object, and a state object, and returns an IAsyncResult while EndGetMessage method takes an IAsyncResult and returns the value. Since the service operation returns IAsyncResult we have to implement it first. And the implementation has been given below,


public class AsyncResult : IAsyncResult,IDisposable
 {
 private AsyncCallback _callback;
 private object _state;
 private ManualResetEvent _manualResetEvent;

public AsyncResult(AsyncCallback callback, object state)
 {
 _callback = callback;
 _state = state;
 _manualResetEvent = new ManualResetEvent(false);
 }

public bool IsCompleted
 {
 get { return _manualResetEvent.WaitOne(0, false); }
 }

public WaitHandle AsyncWaitHandle
 {
 get { return _manualResetEvent; }
 }

public object AsyncState
 {
 get { return _state; }
 }
 public ManualResetEvent AsyncWait
 {
 get { return _manualResetEvent; }

 }
 public bool CompletedSynchronously
 {
 get { return false; }
 }

public void Completed()
 {
 _manualResetEvent.Set();
 if (_callback != null)
 _callback(this);
 }

 public void Dispose()
 {
 _manualResetEvent.Close();
 _manualResetEvent = null;
 _state = null;
 _callback = null;
 }
 }

AsyncResult implements IAsyncResult that has some properties like AsyncCallback, state object and a ManualResetEvent, which handle waiting for asynchronous operation. IsCompleted is used to specify that the operation is completed asynchronously. In the Complete() method ManualResetEvent has been set, which means that the event is signaled now and any other awaiting thread can follow.

Now for our MessageServiceOperation I create MessageAsyncResult which just inherit from AsyncResult to add a Message property.


public class MessageAsyncResult : AsyncResult
 {
 public string Message { get; private set; }
 public MessageAsyncResult(string message, AsyncCallback callback, object state)
 : base(callback, state)
 {
 Message = message;
 }
 }

Now implementing the service operations.


public class MessageService : IMessageService
 {
 public IAsyncResult BeginGetMessage(string message, AsyncCallback callback, object state)
 {
 var replyMessage = string.Format("{0}{1}","Server says :",message);
 var messageAsyncResult = new MessageAsyncResult(replyMessage, callback, state);
 ThreadPool.QueueUserWorkItem(CompleteProcess, messageAsyncResult);

return messageAsyncResult;
 }

private void CompleteProcess(object state)
 {
 var messageAsyncResult = state as MessageAsyncResult;
 messageAsyncResult.Completed();
 }

public string EndGetMessage(IAsyncResult asyncResult)
 {
 var messageAsyncResult = asyncResult as MessageAsyncResult;
 messageAsyncResult.AsyncWait.WaitOne();
 return messageAsyncResult.Message;
 }
 }

In the BeginGetMessage () method I create an instance of MessageAsyncResult by passing appropriate parameters to it then call ThreadPool.QueueUserWorkItem() method to add a method to waiting queue for execution. The method CompleteProcess() will run whenever a thread becomes available and it finally call the Completed() method to release the thread and allow the other operations to execute. In the EndGetMessage () method, I call the WaitOne() method of its ManualResetEvent to wait until the current execution ends then return the Result property.

Service Hosting

This is also very simple. Here I have used a console app which will be used as a server,


class Program
 {
 static void Main(string[] args)
 {
 var svcHost = new ServiceHost(typeof(MessageService));
 Console.WriteLine("Available Endpoints :\n");
 svcHost.Description.Endpoints.ToList().ForEach(endpoints => Console.WriteLine(endpoints.Address.ToString()));
 svcHost.Open();
 Console.ReadLine();
 }
 }

And the configuration for that,


<configuration>
 <system.serviceModel>
 <behaviors>
 <serviceBehaviors>
 <behavior name="">
 <serviceMetadata httpGetEnabled="true" />
 <serviceDebug includeExceptionDetailInFaults="false" />
 </behavior>
 </serviceBehaviors>
 </behaviors>
 <services>
 <service name="Rashim.Rnd.WCF.Asynchronous.Services.MessageService">
 <endpoint address="" binding="basicHttpBinding" contract="Rashim.Rnd.WCF.Asynchronous.Services.IMessageService">
 <identity>
 <dns value="localhost" />
 </identity>
 </endpoint>
 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
 <host>
 <baseAddresses>
 <add baseAddress="http://localhost/Rashim.Rnd.WCF.Asynchronous.Services/" />
 </baseAddresses>
 </host>
 </service>
 </services>
 </system.serviceModel>
</configuration>

Client

Now how client could consume this service.? Here I have given a simple console app to consume this service,


public class Program
 {
 static void Main(string[] args)
 {
 var channelFactory = new ChannelFactory<IMessageService>("MessageServiceEndpoint");
 var proxy = channelFactory.CreateChannel();
 var message = Console.ReadLine();
 while (message.Equals("exit",StringComparison.CurrentCultureIgnoreCase)==false)
 {
 proxy.BeginGetMessage(message, ClientCallBack, proxy);
 message = Console.ReadLine();
 }
 }

private static void ClientCallBack(IAsyncResult ar)
 {
 var res = ar.AsyncState as IMessageService;
 if (res != null)
 {
 var message = res.EndGetMessage(ar);
 Console.WriteLine(message);
 }
 }
 }

And the configuration file for this is,


<configuration>
 <system.serviceModel>
 <bindings />
 <client>
 <endpoint address="http://localhost/Rashim.Rnd.WCF.Asynchronous.Services/"
 binding="basicHttpBinding" contract="Rashim.Rnd.WCF.Asynchronous.Services.IMessageService"
 name="MessageServiceEndpoint">
 <identity>
 <dns value="ServerCertificate" />
 </identity>
 </endpoint>
 </client>
 </system.serviceModel>
</configuration>

That’s it. Download Source code.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: