Search code examples
c#async-awaitwindows-phone-8service-reference

How to handle Service References in Windows Phone 8 without Task-Based proxies


With so much emphasis on Task-Based asynchronous development, I was surprised to see that Service References in Windows Phone 8 do not support task-based implementations. Instead they use a "XYZCompleted" event-based asynchronous approach.

As a result, code like this is necessary: http://codepaste.net/fqyt47

public async Task<IEnumerable<MyService.Character>> GetCharactersAsync()
{
    var _Task = new TaskCompletionSource<IEnumerable<MyService.Character>>();
    var _Client = new MyService.ServiceClient();
    _Client.GetCharactersCompleted += (s, e) =>
    {
        var _Characters = e.Result as IEnumerable<MyService.Character>;
        if (e.Error != null && !_Task.TrySetException(e.Error))
            System.Diagnostics.Debugger.Break();
        else if (e.Cancelled && !_Task.TrySetCanceled())
            System.Diagnostics.Debugger.Break();
        else if (!_Task.TrySetResult(_Characters))
            System.Diagnostics.Debugger.Break();
    };
    _Client.GetCharactersAsync();

    return await _Task.Task;
}

However, this feels wrong. Is there a better, more elegant approach?


Solution

  • I'm surprised Windows Phone 8 doesn't have Task-based reference creation.

    That said, TaskCompletionSource is the standard way of interoperating with various asynchronous patterns (including EAP).

    Usually it's done with extension methods which are consumable by await but which are not async themselves:

    public Task<IEnumerable<MyService.Character>> GetCharactersTaskAsync(this ServiceClient client)
    {
      var tcs = new TaskCompletionSource<IEnumerable<MyService.Character>>();
      client.GetCharactersCompleted += (s, e) =>
      {
        if (e.Error != null) tcs.SetException(e.Error);
        else if (e.Cancelled) tcs.SetCanceled();
        else tcs.SetResult(e.Result);
      };
      client.GetCharactersAsync();
      return tcs.Task;
    }