Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Microsoft.bcl.async in PCL with Mono Droid?

I have a Portable Class Library (PCL) targeted at Profile158 (Windows Store, .NET 4.5, Silverlight 5, Windows Phone 8). I can easily work with methods that return a type of Task, and it all works as I would expect. Whenever I access the Result property, it finishes running the asynchronous code and returns the result.

However, if I use the async/await keywords in a method inside the PCL, I get a task back. However, when I attempt to access the Result property, it blocks and never returns.

Looking at the debug output window in Visual Studio in both cases I see the same text:

Thread started: 
Thread started: 
Loaded assembly: Mono.Security.dll [External]
Thread started: 
Thread started: 

So it appears as if the code is being run, but it never returns to the UI thread. Has anyone else tried to use a PCL with Microsoft.bcl.async in the PCL?

My Mono Droid project is targeted at Android 2.1.

Thanks, -- John

Update:
Here is some additional information about the different scenarios. First, here is code that does work on Mono Droid when written in the UI code:

var task = request.GetResponseAsync();
string html = task.Result.GetResponseText();

I then created the following method in the PCL:

public async Task<string> Test()
{
    IHttpResponse responce = await GetResponseAsync();
    return responce.GetResponseText();
}

And call it with this code from the Mono UI code:

string html = request.Test().Result;

it never returns...

like image 391
John Socha-Leialoha Avatar asked Oct 22 '22 18:10

John Socha-Leialoha


1 Answers

This is a classic deadlock scenario, as I describe on my blog.

By default, await will capture a "context" and use it to resume the async method. This "context" is the current SynchronizationContext unless it is null, in which case it's the current TaskScheduler.

So, you're calling an async method from a UI thread (which provides a SynchronizationContext), then blocking the UI thread by calling Result. The async method cannot finish because it is trying to finish on the UI thread, which is blocked.

To fix this, follow these guidelines:

  1. Use async all the way down. Don't call Result or Wait on Tasks returned from async methods; use await instead.
  2. Use ConfigureAwait(false) whenever possible in your library code.

You may also find my async/await intro helpful.

like image 50
Stephen Cleary Avatar answered Jan 02 '23 19:01

Stephen Cleary