Async C# 5: Using Async Pattern with WCF and Silverlight

Sometime ago I published a way to use WCF service with the new Async Pattern in C#. The problem is that this approach won’t work with Silverlight. More specifically, TaskFactory is not available in Silverlight.

So.. here is one solution (it does not provide full functionality as in TaskFactory, but you can manage 90% of use cases):

MyTaskFactory
public static class MyTaskFactory
{
    public static Task<TResult> FromAsync<TResult>(
        IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
    {
        var completionSource = new TaskCompletionSource<TResult>();
        if (asyncResult.IsCompleted)
        {
            completionSource.TrySetResult(asyncResult, endMethod);
        }
        else
        {
            System.Threading.ThreadPool.RegisterWaitForSingleObject(
                asyncResult.AsyncWaitHandle,
                (state, timeOut) =>
                {
                    completionSource.TrySetResult(asyncResult, endMethod);
                }, null, -1, true);
        }

        return completionSource.Task;
    }

    static void TrySetResult<TResult>(
        this TaskCompletionSource<TResult> completionSource,
        IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
    {
        try
        {
            var result = endMethod(asyncResult);
            completionSource.TrySetResult(result);
        }
        catch (OperationCanceledException)
        {
            completionSource.TrySetCanceled();
        }
        catch (Exception genericException)
        {
            completionSource.TrySetException(genericException);
        }
    }
}

The previous code fragment defines a helper method that behaves similar to TaskFactory.

Usage example:

Usage:
var client = new MyServiceClient();
// EchoTaskAsync is an extension method
var result = await client.EchoTaskAsync("zzzz");

And here is the service extension for MyServiceClient (Note that I use the service interface contract instead of the ClientBase<> as parameter since we need access to Begin/End methods):

Service Async Extensions
public static class ServiceExtensions
{
    public static Task<string> EchoTaskAsync(
        this IMyService client, string text)
    {
        return MyTaskFactory.FromAsync<string>(
            client.BeginEcho(text, null, null),
            ar => client.EndEcho(ar));
    }
}

Try it and let me know if it works for you..

2 Comments

  • Hey thanks for the post.
    I did the extension as you mentioned. But when I try to call the method with await, I get following error message:

    The 'await' operator can only be used in a method or lambda marked with the 'async' modifier

    Do I miss something in your code snippets?
    my extension method is very straight forward:

    public static Task<IEnumerable> GetPatientsTaskAsync(this PatientServiceClient client)
    {
    var i = client as IPatientService;
    return MyTaskFactory.FromAsync<IEnumerable>(i.BeginGetPatients(null, null),i.EndGetPatients);
    }

    thanks for any help
    dave

  • Hi Dave,
    You must mark the method in which you are using the await pattern with the async modifier, as in:
    async void MyMethod()
    {
    await SomeMethod();
    }

Comments have been disabled for this content.