Reputation: 160
I have a window, which uses some async methods. However, it only hangs UI (during these operations) only if i create it on runtime, like this:
private void button_Click(object sender, RibbonControlEventArgs e)
{
AboutWindow SettingsWindow = new AboutWindow();
SettingsWindow.ShowDialog();
}
However, if I create it like this:
private AboutWindow SettingsWindow = new AboutWindow();
private void button_Click(object sender, RibbonControlEventArgs e)
{
SettingsWindow.ShowDialog();
}
Everything seems to be OK and UI is not hanging.
The methods inside the window, that cause the problems are presented below:
private async void CallUpdateDownload()
{
UpdaterStatus.CurrentUpdateStatus = await DownloadAndSaveInstallerAsync(UpdaterStatus.freshVersion);
}
public static async Task<UpdateStatus> DownloadAndSaveInstallerAsync(string NewVersion)
The main hang occurs on this string inside DownloadAndSaveInstallerAsync
:
CloudBlockBlob blob = new CloudBlockBlob(new Uri(sas));
MemoryStream msRead = new MemoryStream();
blob.DownloadToStream(msRead); // HANGS HERE
The question is, why this happens? Why creating the window on start prevents it from hanging from async methods.
The other question is, that I have another object, which also uses DownloadAndSaveInstallerAsync
method. These objects are created on runtime, and I can't do anything to prevent this hanging, occuring on download.
How can I prevent UI from hanging in this situation (creating objects on runtime)?
More code below:
private async void CallUpdateDownload()
{
UpdaterStatus.CurrentUpdateStatus = await UpdaterLogic.DownloadAndSaveInstallerAsync(UpdaterStatus.freshVersion);
}
UpdaterLogic:
public static async Task<UpdateStatus> DownloadAndSaveInstallerAsync(string NewVersion)
{
//...
if (await SaveInstallerToMemoryAsync(NewVersion))
{
return UpdateStatus.ReadyToInstall;
}
else
{
return UpdateStatus.Error;
}
}
private static async Task<bool> SaveInstallerToMemoryAsync(string NewVersion)
{
using (MemoryStream ms = await UpdaterClient.DownloadInstallerAsync(NewVersion))
using (FileStream fs = new FileStream(UpdaterSettings.Path), FileMode.Create))
{
if (ms == null) return false;
ms.Position = 0;
await ms.CopyToAsync(fs);
fs.Close();
ms.Close();
return true;
}
}
UpdaterClient:
public static async Task<MemoryStream> DownloadInstallerAsync(string version)
{
string sas = await GetInstallerDownloadLinkAsync(version);
CloudBlockBlob blob = new CloudBlockBlob(new Uri(sas));
MemoryStream msRead = new MemoryStream();
blob.DownloadToStream(msRead);
return msRead;
}
public static async Task<string> GetInstallerDownloadLinkAsync(string version)
{
HttpResponseMessage response = null;
response = await httpClient.GetAsync(UpdaterSettings.Link + version);
if (response.IsSuccessStatusCode)
{
var res = await response.Content.ReadAsStringAsync();
return res.Trim('"');
}
}
Upvotes: 1
Views: 970
Reputation: 19106
You have to execute the long running parts inside a task/thread and await
them to avoid blocking.
public static async Task<MemoryStream> DownloadInstallerAsync(string version)
{
string sas = await GetInstallerDownloadLinkAsync(version);
CloudBlockBlob blob = new CloudBlockBlob(new Uri(sas));
MemoryStream msRead = new MemoryStream();
await Task.Run( () => blob.DownloadToStream(msRead) );
return msRead;
}
Update
CloudBlockBlob
does offer an DownloadToStreamAsync
method which you can use
public static async Task<MemoryStream> DownloadInstallerAsync(string version)
{
string sas = await GetInstallerDownloadLinkAsync(version);
CloudBlockBlob blob = new CloudBlockBlob(new Uri(sas));
MemoryStream msRead = new MemoryStream();
await blob.DownloadToStreamAsync(msRead);
return msRead;
}
Upvotes: 1