Reputation: 718
I can't seem to get async to work the way I want. I'm pretty unfamiliar with it in general, but my research has led me to it. Here's my situation: I have a XAML form I'm loading that needs data from a web service. I can get the data, no problem. The issue is that I want the form to load with a "Please wait. Data loading..." screen that I have made, but nothing loads until the query finishes which can take up to 10 seconds, which is a poor user experience. Can anyone let me know what I'm doing wrong?
In my ViewModel main section, I call LoadData() to get the ball rolling.
I also had a thought...is async what I really want here?
public async void LoadData()
{
IsLoading = Visibility.Visible;
MonitorData downloadInfo = await GetWebApiInfo();
try
{
AssignDataToControls(downloadInfo);
IsLoading = Visibility.Collapsed;
Console.WriteLine("Loaded successfully.");
}
catch (Exception e)
{
IsLoading = Visibility.Collapsed;
Console.WriteLine("Error: " + e);
}
}
private void AssignDataToControls(MonitorData mon)
{
MainPanel.Clear();
mon.MainPanel.ToList().ForEach(x => MainPanel.Add(x));
Information = mon.Information;
MonitorText = mon.MonitorText;
ProgressData = mon.progList;
}
public async Task<MonitorData> GetWebApiInfo()
{
main = new MonitorData();
var url = "::::::::WEB API ADDRESS::::::::";
var request = (HttpWebRequest)WebRequest.Create(url);
//Task<HttpWebRequest> req = await (HttpWebRequest)WebRequest.Create(url);
//HttpWebRequest request = await GetWebRequest(url);
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream, Encoding.Unicode);
string responseFromServer = reader.ReadToEnd();
var deserializer = new JavaScriptSerializer();
main = deserializer.Deserialize<MonitorData>(responseFromServer);
reader.Dispose();
response.Dispose();
return main;
}
Upvotes: 1
Views: 1072
Reputation: 457382
The compiler will tell you exactly what's wrong with that approach. Specifically, your GetWebApiInfo
method is going to run synchronously because you never use await
.
In this case, you can use HttpClient
to download the information asynchronously. It's a lot easier than mucking around with WebResponse
and stuff:
private static readonly HttpClient _client = new HttpClient();
public async Task<MonitorData> GetWebApiInfo()
{
var url = "::::::::WEB API ADDRESS::::::::";
string responseFromServer;
using (var dataStream = await _client.GetStreamAsync())
using (var reader = new StreamReader(dataStream, Encoding.Unicode))
responseFromServer = await reader.ReadToEndAsync();
var deserializer = new JavaScriptSerializer();
return deserializer.Deserialize<MonitorData>(responseFromServer);
}
In general, when you want to "make something async", you should start from the lowest-level APIs. E.g., don't start by marking GetWebApiInfo
with async
; start with the actual HTTP transfer and call it with await
. Then let async
/await
grow from there.
You may find my NotifyTask<T>
type helpful; it allows you to do things like show/hide busy indicators with data binding.
Upvotes: 3