C# 异步下载不通过IProgress.Report报告

C# 异步下载不通过IProgress.Report报告,c#,windows-phone-8,asynchronous,async-await,windows-phone-8.1,C#,Windows Phone 8,Asynchronous,Async Await,Windows Phone 8.1,我面临着一个奇怪的问题,我必须承认——我不明白。我有一个任务,从Web异步下载一个文件: public async Task DownloadFile(Uri requestUri, string fileName, IProgress<int> progress) { HttpWebRequest request = HttpWebRequest.CreateHttp(requestUri); request.Method = "GET"; request.

我面临着一个奇怪的问题,我必须承认——我不明白。我有一个任务,从Web异步下载一个文件:

public async Task DownloadFile(Uri requestUri, string fileName, IProgress<int> progress)
{
    HttpWebRequest request = HttpWebRequest.CreateHttp(requestUri);
    request.Method = "GET";
    request.AllowReadStreamBuffering = false;
    using (WebResponse response = await request.GetResponseAsync())
    using (Stream mystr = response.GetResponseStream())
    {
        StorageFolder local = ApplicationData.Current.LocalFolder;
        StorageFile file = await local.CreateFileAsync(fileName);
        using (Stream fileStream = await file.OpenStreamForWriteAsync())
        {
            const int BUFFER_SIZE = 100 * 1024;
            byte[] buf = new byte[BUFFER_SIZE];
            int bytesread = 0;
            // the problem is here below
            while ((bytesread = await mystr.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
            {
                await fileStream.WriteAsync(buf, 0, bytesread);
                progress.Report(bytesread);
            }
        }
    }
}
公共异步任务下载文件(Uri请求Uri、字符串文件名、IProgress进度)
{
HttpWebRequest-request=HttpWebRequest.CreateHttp(requestUri);
request.Method=“GET”;
request.AllowReadStreamBuffering=false;
使用(WebResponse=await request.GetResponseAsync())
使用(Stream mystr=response.GetResponseStream())
{
StorageFolder local=ApplicationData.Current.LocalFolder;
StorageFile file=await local.CreateFileAsync(文件名);
使用(Stream fileStream=await file.OpenStreamForWriteAsync())
{
const int BUFFER_SIZE=100*1024;
字节[]buf=新字节[缓冲区大小];
int字节读取=0;
//问题就在下面
而((bytesread=await mystr.ReadAsync(buf,0,BUFFER_SIZE))>0)
{
等待fileStream.WriteAsync(buf,0,字节读取);
进度报告(bytesread);
}
}
}
}
任务正在运行,但正如您所见,它应该报告其进度

问题是,当程序点击
bytesread=await mystr.ReadAsync(buf,0,BUFFER\u SIZE)
行时,它不会在该线程上执行任何其他操作,直到整个文件下载完毕(不仅是
BUFFER\u SIZE
)。在完成下载后,
while
循环被触发了很多次,它需要从内存中复制流,这非常快


奇怪的是,相同的代码在WP8.0上运行时没有问题,现在我尝试在WP8.1上运行它,我面临这个问题。有人知道我做错了什么吗

需要记住的一件事是,
IProgress.Report
本身就是“异步的”。不是因为它返回了一个
任务
,而是因为进度报告实现可能在
报告
返回时没有完成其实际进度报告。特别是,
Progress.Report
将在调用其委托或事件处理程序之前将进度报告封送到捕获的
SynchronizationContext

通常,这正是您想要的:如果在UI线程上创建
进度
,则其委托/事件处理程序将在UI线程上执行,并且在使用进度报告更新UI时,您不必担心跨线程封送

在本例中,我相信您看到的是WP8.1的一些攻击性缓存。微软一直在推动WP上的缓存。如果我的猜测是正确的,那么您看到的行为是由于同步完成的
ReadAsync
(响应已经在HTTP缓存中)以及同步完成的
WriteAsync
(缓冲文件写入)。在这种情况下,
await
s中没有一个会实际产生,因此
IProgress.Report
调用会堆积起来,等待在UI线程上运行


缓存通常只是开发过程中的一个“问题”。如果您确实希望最终用户遇到这种情况,则可以添加一个
wait Task.Yield()进入你的
循环。

我认为你对缓存的猜测是正确的。我调试了更多,我看到的是程序在ReadAsync停止(可能将所有内容下载到缓存中),然后立即继续。我不知道在这种情况下该怎么办。我已经禁止ReadStreamBuffering,因此它应该可以工作(就像在WP8上一样)。如果要阻止缓存,则需要让服务器发送一个关闭缓存的缓存头,或者向URL附加一个唯一/随机值(并确保服务器忽略它).我已经试过了,问题不在于下载相同的Url,而是当程序点击行
bytesread=wait mystr.ReadAsync(buf,0,BUFFER\u SIZE))
时,它会停止并等待整个文件从web下载,而不仅仅是
BUFFER\u SIZE
,在下载之后,其余的操作在内存上执行得相当快。这确实是令人惊讶的行为。