Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing an async WCF service

I have a WPF application which I'm currently working on separating into a client and server side - using WCF. I did not like the mess I initially got with the straight forward solution, so now I'm restructuring following the recommendations in the screencast of Miguel Castro, WCF Extreme. If you're not familiar with the video he basically sets up the whole communication manually - without using service references. This includes:

  • A common Contract with all service and data contracts - referenced by the client and server
  • A console application hosting the service
  • Proxy classes on the client mapping up the service, and passing calls to it (using ClientBase or ClientFactory)

I've followed all his steps, and I really like where this is going. However, he does not address asynchronous service calls, and this is what I'd like to use.

When adding a Service Reference I can check a "Generate async operations" checkbox, and I get MyServiceCompleted and MyServiceAsync. However, I guess this is something which was generated when adding the service reference, and not some magic in the classes this builds on?

So, can I get async operations from ClientBase or ClientFactory somehow? Or do I have to define the actual server side services to be async? If so - could someone please give me a few hints or examples on how to get started with a simple async service? I've been reading around on MSDN on the subject, but it has left me all confused feeling like an idiot for not getting this already..

like image 836
stiank81 Avatar asked Dec 11 '09 20:12

stiank81


People also ask

How do you call async method in WCF?

To call a WCF service method asynchronously you need to create an AsyncCallback delegate and pass this delegate to the asynchronous proxy method. Note that the AsyncCallback delegate is executed on a worker thread and so this doesn't block the main thread of the application.

How to create asynchronous method in WCF service c#?

In client project solution explorer right click and select "Add Service reference". Now click on "Advanced" button in the Add Service reference dialog box and select "Generate Asynchronous Operations" check box. It will generate IAsyncResult class and two methods Begin<OperationName> and End<OperationName>.

What is asynchronous messages in WCF?

In Windows Communication Foundation (WCF) applications, a service operation can be implemented asynchronously or synchronously without dictating to the client how to call it. For example, asynchronous service operations can be called synchronously, and synchronous service operations can be called asynchronously.

How do you call operations asynchronously using a channel factory?

To access a service operation asynchronously, create the client and call the Begin[Operation] (for example, BeginAdd ) and specify a callback function, as shown in the following sample code. When the callback function executes, the client calls End<operation> (for example, EndAdd ) to retrieve the result.


2 Answers

Implementing async operations on server side is quite simple. Make sure you method names match and are prefixed with Begin and End. GetImageAsyncResult is a custom IAsyncResult implementation (lots of examples on web).

    public class MapProvider : IMapProvider //implementation - belongs to server
    {
         public IAsyncResult BeginGetImage(int level, int x, int y, string[] layers, AsyncCallback callback, object state)
         {
              GetImageAsyncResult asyncResult = new GetImageAsyncResult(level, x, y, layers, callback, state);
              ThreadPool.QueueUserWorkItem(Callback, asyncResult);
              return asyncResult;
         }

         private void Callback(object state)
         {

              GetImageAsyncResult asyncResult = state as GetImageAsyncResult;
              asyncResult.Image = TileProvider.GetImage(asyncResult.Level, asyncResult.X, asyncResult.Y, asyncResult.Layers);
              asyncResult.Complete();
         }

         public System.Drawing.Bitmap EndGetImage(IAsyncResult result)
         {
              using (GetImageAsyncResult asyncResult = result as GetImageAsyncResult)
              {
                   asyncResult.AsyncWait.WaitOne();
                   return asyncResult.Image;
              }
         }
    }

    public class MapProviderProxy : ClientBase<IMapProvider>, IMapProvider, IDisposable
    {
         public IAsyncResult BeginGetImage(int level, int x, int y, string[] layers, AsyncCallback callback, object state)
         {
              return Channel.BeginGetImage(level, x, y, layers, callback, state);
         }

         public System.Drawing.Bitmap EndGetImage(IAsyncResult result)
         {
              return Channel.EndGetImage(result);
         }

         public void Dispose()
         {
              if (State == CommunicationState.Faulted)
              {
                   Abort();
              }
              else
              {
                   try
                   {
                        Close();
                   }
                   catch
                   {
                        Abort();
                   }
              }
         }
    }
like image 142
Goran Avatar answered Sep 21 '22 22:09

Goran


When you select "Generate async operations", as you noted, there is no magic involved: Begin... will start your communication, server starts processing stuff, but you can't use anything until you call End....

All this behavior happens at client-side, so you don't need to change anything at your service implementation.

You're probably thinking this must be complex, but it don't ;)

EDIT: Here go an example:

using (Service.SampleClient client = new Service.SampleClient())
{
    client.AddCompleted += 
        (object sender, Service.AddCompletedEventArgs e)
            {
                Console.WriteLine(e.Result); // 2
            };
    client.AddAsync(1, 1);

    // wait for async callback
    Console.ReadLine();
}

[ServiceContract]
public interface ISample
{
    [OperationContract]
    int Add(int a, int b);
}

You can also to explicitly program your service to work async, as describe here: Synchronous and Asynchronous Operations, by using [OperationContract(AsyncPattern=true)]

like image 27
Rubens Farias Avatar answered Sep 18 '22 22:09

Rubens Farias