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:
- My
ListView
shows theCustomObjects
that i define in the constructor. Since i could not use the await keyword in my constructor, I was expecting that the call ofGetWebResponseAsync().ConfigureAwait(false)
would block my UI-Thread and produce a deadlock (like replacing the call withGetWebResponseAsync().Wait()
is doing). It seems likeConfigureAwait(false)
already makes my method run on another thread even though i did not run it as a task or await it? - 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
}