使用 HttpWebRequest 时应用挂起
App hangs when use HttpWebRequest
我正在使用 C# 开发一个从 Internet 下载文件的应用程序(我不想使用后台下载器!)
这是 class 下载代码:
public class DL
{
public event Progresses OnProgress;
Stopwatch stopwatch = new Stopwatch();
public async void Get(string url, StorageFile destinationFile)
{
stopwatch.Reset();
stopwatch.Start();
HttpWebRequest request = (HttpWebRequest)WebRequest.
Create(url);
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
long size = response.ContentLength;
long downloaded = 0;
using (Stream inputStream = response.GetResponseStream())
using (Stream outputStream = await destinationFile.OpenStreamForWriteAsync())
{
byte[] buffer = new byte[1024];
int bytesRead;
do
{
bytesRead = inputStream.Read(buffer, 0, buffer.Length);
downloaded += bytesRead;
outputStream.Write(buffer, 0, bytesRead);
int secondsRemaining = (int)(stopwatch.Elapsed.TotalSeconds
/ downloaded * (size - downloaded));
TimeSpan span = new TimeSpan(0, 0, 0, secondsRemaining);
string remainTime = string.Format("{0}:{1}:{2}", span.Hours, span.Minutes, span.Seconds);
OnProgress(remainTime);
} while (bytesRead != 0);
}
}
}
public delegate void Progresses(string text);
这是下载文件的方法:
private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
DL webGard = new DL();
webGard.OnProgress += WebGard_OnProgress;
StorageFile destinationFile = await KnownFolders.MusicLibrary
.CreateFileAsync("r58.zip", CreationCollisionOption.GenerateUniqueName);
string url = "my url";
webGard.Get(url, destinationFile);
}
private async void WebGard_OnProgress(string text)
{
System.Diagnostics.Debug.WriteLine(text);
var dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
textBlock.Text = text;
});
}
当我按下下载按钮时,应用程序当前挂起并且在下载结束之前无法使用它,我想向用户显示剩余时间并且此代码适用于 [=20= 中的输出 windows ] 但 UI 被挂起,无法在 textBlock 中显示结果。
我该如何解决这个问题?
谢谢
这里的问题是您使用了所有正确的异步命令来启动,这很好。不幸的是,当您实际从流中读取数据时,您是在同步执行所有这些操作。这就是我的意思...
初始化流后,您就可以开始使用循环读取和写入数据。如果您查看 do/while 循环,您会发现所有操作都是同步完成的。此循环中有两个工作项导致您的应用挂起。这一行:
bytesRead = inputStream.Read(buffer, 0, buffer.Length);
和这一行:
outputStream.Write(buffer, 0, bytesRead);
在循环的每次迭代中,您将阻塞应用程序线程,同时等待服务器对下一个数据块的响应。这意味着您不仅在等待服务器回复,还在等待通过网络传输此数据的延迟。最重要的是,当您将这些数据写回您的文件时,您将被文件系统阻止。相反,您应该使用流的 ReadAsync and WriteAsync 方法。
这样,当您实际在内存中移动数据时,您实际上只会在很短的时间内阻塞主线程。然后你又回到等待流完成它们的操作,而你的应用程序 UI 线程可以自由地做它想做的事。
希望对您有所帮助!
我正在使用 C# 开发一个从 Internet 下载文件的应用程序(我不想使用后台下载器!) 这是 class 下载代码:
public class DL
{
public event Progresses OnProgress;
Stopwatch stopwatch = new Stopwatch();
public async void Get(string url, StorageFile destinationFile)
{
stopwatch.Reset();
stopwatch.Start();
HttpWebRequest request = (HttpWebRequest)WebRequest.
Create(url);
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
long size = response.ContentLength;
long downloaded = 0;
using (Stream inputStream = response.GetResponseStream())
using (Stream outputStream = await destinationFile.OpenStreamForWriteAsync())
{
byte[] buffer = new byte[1024];
int bytesRead;
do
{
bytesRead = inputStream.Read(buffer, 0, buffer.Length);
downloaded += bytesRead;
outputStream.Write(buffer, 0, bytesRead);
int secondsRemaining = (int)(stopwatch.Elapsed.TotalSeconds
/ downloaded * (size - downloaded));
TimeSpan span = new TimeSpan(0, 0, 0, secondsRemaining);
string remainTime = string.Format("{0}:{1}:{2}", span.Hours, span.Minutes, span.Seconds);
OnProgress(remainTime);
} while (bytesRead != 0);
}
}
}
public delegate void Progresses(string text);
这是下载文件的方法:
private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
DL webGard = new DL();
webGard.OnProgress += WebGard_OnProgress;
StorageFile destinationFile = await KnownFolders.MusicLibrary
.CreateFileAsync("r58.zip", CreationCollisionOption.GenerateUniqueName);
string url = "my url";
webGard.Get(url, destinationFile);
}
private async void WebGard_OnProgress(string text)
{
System.Diagnostics.Debug.WriteLine(text);
var dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
textBlock.Text = text;
});
}
当我按下下载按钮时,应用程序当前挂起并且在下载结束之前无法使用它,我想向用户显示剩余时间并且此代码适用于 [=20= 中的输出 windows ] 但 UI 被挂起,无法在 textBlock 中显示结果。
我该如何解决这个问题? 谢谢
这里的问题是您使用了所有正确的异步命令来启动,这很好。不幸的是,当您实际从流中读取数据时,您是在同步执行所有这些操作。这就是我的意思...
初始化流后,您就可以开始使用循环读取和写入数据。如果您查看 do/while 循环,您会发现所有操作都是同步完成的。此循环中有两个工作项导致您的应用挂起。这一行:
bytesRead = inputStream.Read(buffer, 0, buffer.Length);
和这一行:
outputStream.Write(buffer, 0, bytesRead);
在循环的每次迭代中,您将阻塞应用程序线程,同时等待服务器对下一个数据块的响应。这意味着您不仅在等待服务器回复,还在等待通过网络传输此数据的延迟。最重要的是,当您将这些数据写回您的文件时,您将被文件系统阻止。相反,您应该使用流的 ReadAsync and WriteAsync 方法。
这样,当您实际在内存中移动数据时,您实际上只会在很短的时间内阻塞主线程。然后你又回到等待流完成它们的操作,而你的应用程序 UI 线程可以自由地做它想做的事。
希望对您有所帮助!