Johan Paul
Johan Paul

Reputation: 2466

Working with Background File Transfer with Task.Wait()

I am working with a 3rd party library that is event based. I am really only interested in calling a library method and knowing when the library has finished. Pretty much like here: Convert Event based pattern to async CTP pattern

The thing is that the library seems to use Windows Phone's Background File Transfer to do its job.

My symptom is that the library's completion handler is called only after my Task.Wait(TimeSpan.FromSeconds(5)) has timed out.

I tried to search for some docs about running Background File Transfer in the ThreadPool (as I assume in my async code, that's where the library is running), but couldn't really find any information. So could my issue (that completion handler is called only after timeout) be that Background File Transfer code shouldn't run in the ThreadPool?

Any ideas what a good approach for this kind of problem would be?

Upvotes: 1

Views: 186

Answers (1)

noseratio
noseratio

Reputation: 61726

The pattern you linked is correct. It doesn't use async/await but it doesn't use Task.Wait() either. It returns a Task object, and you're expected to await on that task asynchronously. Which means, the code after await task will be asynchronously invoked by the Task Scheduler when the task has reached the complete (faulted, cancelled) state.

Otherwise, you're blocking the UI thread and its message pump with the synchronous Task.Wait() call, so the completion event doesn't have a chance to get fired properly.

To understand this issue better, here is a very good read: Don't Block on Async.

To correct your code, you'd have to make the whole chain of calls async, up to the root, which in a UI app is usually an event handler. E.g.:

// note, "async void" is normally only good for async event handler
async void buttonTest_Click(object sender, EventArgs e)
{
    try
    {
        var task = DownloadStringAsync("http://example.com"); // for example 
        // Wrong: task.Wait();      
        await task;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

On a side note, now you've got other things to worry about. The UI is not blocked any more, while the asynchronous operation is still in progress. So, your user may click the Test button again, and you're suddenly having two pending async operations. You should account for such scenario (it's been widely discussed here on SO as well).

Upvotes: 1

Related Questions