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?
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;
}