2

Apparently i did not understand async/await yet and the following basic example already causes some headache:

For test purposes i create a Window which represents my UI for now and i want to fire an asynchronous method which does some work in the background when the window opens. I added a Listview to my window to test if the UI is responding.

When i execute the following code, two things happen that i do not understand:

  1. My ListView shows the CustomObjects that i define in the constructor. Since i could not use the await keyword in my constructor, I was expecting that the call of GetWebResponseAsync().ConfigureAwait(false) would block my UI-Thread and produce a deadlock (like replacing the call with GetWebResponseAsync().Wait() is doing). It seems like ConfigureAwait(false) already makes my method run on another thread even though i did not run it as a task or await it?
  2. The UI shows up, but freezes while the Async method is running. This is actually not unexpected but confuses me if i consider the previous observation that the Listview is apparently accessible from the code while i perform my async method. Doesn't that mean that my UI-Thread is NOT blocked and thus I should be able to interact with the UI?

Since i got stuck here, i would also like to know how i can properly call my async method in the constructor right away. If i use await GetWebResponseAsync().ConfigureAwait(false); it doesn't compile since my constructor does not have the async keyword. However i know by now that i should not use async void (and even if i try to make my constructor an async void method, it doesn't compile because member names can not be the same as their enclosing type).

public partial class TitleWindow : Window
{
    public TitleWindow()
    {
        InitializeComponent();

        // I can not use this because the constructor is not async.
        //Task tempTask = await GetWebResponseAsync().ConfigureAwait(false);

        GetWebResponseAsync().ConfigureAwait(false);

        //This should in theory test if my UI-Thread is blocked?!
        List<CustomObject> items = new List<CustomObject>();
        items.Add(new CustomObject() { Title = "CustomTitle", Year = 2100});
        items.Add(new CustomObject() { Title = "CustomTitle2", Year = 2015});
        lvTitles.ItemsSource = items;

    }

    public async Task GetWebResponseAsync(){
        WebRequest request = WebRequest.Create("http://www.google.com");
        request.Credentials = CredentialCache.DefaultCredentials;
        WebResponse response = await request.GetResponseAsync();

        //Output for test purposes.
        Stream dataStream = response.GetResponseStream();
        StreamReader reader = new StreamReader(dataStream);
        string responseFromServer = await reader.ReadToEndAsync();
        Console.WriteLine(responseFromServer);
        return;
    }
}

Update:

Yuval Itzchakovs Answer works perfectly fine for me.

Also this pattern (taken from the link in Yuval Itzchakovs answer) or a combination of both seems like the way to go in a more complex scenario. This provides a very comfortable possibility to ensure later on that the async code from the constructor is already completed by awaiting my Initialization Property.

public partial class TitleWindow : Window, IAsyncInitialization
{
    public Task Initialization{get; private set;}

    public TitleWindow()
    {
        InitializeComponent();
        Initialization = GetWebResponseAsync();
    }

    public async Task GetWebResponseAsync(){
          //unchanged
    }
H W
  • 2,556
  • 3
  • 21
  • 45

1 Answers1

6

It seems like ConfigureAwait(false) already makes my method run on another thread even though i did not run it as a task or await it?

That's incorrect. The method will run synchronously until hitting the first await keyword. After that, since you're not using ConfigureAwait(false) in GetWebResponseAsync, it will marshal it's continuation again back onto the UI thread, which is probably why you're seeing you UI get stuck.

Doesn't that mean that my UI-Thread is NOT blocked and thus I should be able to interact with the UI?

Again, no. The async method isn't running on a background thread, it's consumed on the UI thread. When the method runs its synchronous part (such as Stream dataStream = response.GetResponseStream();) it's still executing on the UI thread.

Calling async method from a constructor doesn't naturally work because constructors aren't async (Stephan Cleary has a good blog post about that).

What you can do is use is attach to an event which fires after the window is loaded, such as the Loaded event, which you can execute async methods inside properly:

this.Loaded += OnWindowLoaded;

And then you can properly await:

private async void OnWindowLoaded(object sender, RoutedEventArgs e)
{
    await GetWebResponseAsync().ConfigureAwait(false);
}

Note that if there's no need for the synchronization context inside GetWebResponseAsync, you can also use ConfigureAwait(false) and save yourself the overhead of the sync context marshaling.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • cool, this works like a charm :) I think i also understood your very clear explanations. Thank you! – H W Feb 19 '15 at 12:59
  • Yes. It was actually running on your UI thread. You can test this by printing the `ManagedThreadId` prior to printing the response. That happens because you're not using `ConfigureAwait(false)` inside your web request method. – Yuval Itzchakov Feb 19 '15 at 13:01
  • I've got one more question: The link you provided has a chapter "What NOT to do" at the very end. Doesn't wiring up my async method to the load event like you suggested have the same drawbacks as the example in that chapter of Stephen Clearys blog post? In my minimalistic example your suggestion works perfectly fine of course since I don't need to know when the async method is done initializing my object. However after reading the blog post i think I should not be using this in general unless i provide internal errorhandling and can ensure that the object is properly initialized already? – H W Feb 19 '15 at 13:47
  • @HW I'm not really understanding your question. If you're wiring it to the loaded event, you have full control of error handling, unlike when you fire it inside the constructor, and you have no control over it. Once you `await`, any exception will propagate up the call-chain until it reaches the highest `await`, which in this case is your event handler, which can be wrapped with a `try-catch` if necessary. – Yuval Itzchakov Feb 19 '15 at 13:50
  • @HW In the what not to do section, stephan **fires the async method inside the constructor**. That's what he's recommending not to do. We're not doing that, we're registering to a UI based event only, and executing once the window has loaded. – Yuval Itzchakov Feb 19 '15 at 13:53
  • 1
    I think you understood my question perfectly fine and the answer was just too obvious ^^ I did not see right away that this is in fact different than firing the async method right in the constructor - thank you! – H W Feb 19 '15 at 13:56