【问题标题】:Using HTTP Client to download a file from MVC causes "(System.AggregateException) One or more errors occurred"使用 HTTP 客户端从 MVC 下载文件导致“(System.AggregateException)发生一个或多个错误”
【发布时间】:2014-10-15 23:40:15
【问题描述】:

我已经将这段代码投入生产很长时间了,而这个问题才刚刚开始。基本上它是从 MVC 控制器下载文件。这些文件大约 5 到 20 兆字节。这是一个在 iOS 上运行的 PCL 库。用户从服务器下载文件时遇到错误。我假设这是一个超时,但我不是 100% 确定。我们无法在内部重新创建此问题,但我们在日志中看到错误并且用户已报告此问题。

我可以在服务器端做些什么来改善这一点?客户没有任何改变,这已成为我们客户群的普遍问题。

服务器代码

    public virtual FileResult BuildDatabaseForSite(Guid organizationId, Guid siteId) {
        var basePath = RESTContext.Config.DBPath;
        var filePath = basePath + @"\" + fileId + ".db";
        byte[] existingDbBytes = null;

        using (new Impersonator(RESTContext.Config.VideoPathUsername, RESTContext.Config.VideoPathDomain,
            RESTContext.Config.VideoPathPassword)) {

            if (System.IO.File.Exists(filePath))
                existingDbBytes = System.IO.File.ReadAllBytes(filePath);
        }                        
        return File(existingDbBytes, "application/octet-stream", "CompassLocal.db");
    }

客户端代码

       public void DownloadDatabase(Guid organizationId, Guid siteId) {
            Platform.FileSystem.DeleteFile(Paths.LocalDatabase);
            var url = string.Format("organizations/{0}/Sites/{1}/InitialDatabaseCompressed", organizationId, siteId);
            var webClient = new HttpClient();
            webClient.Timeout = new TimeSpan(0,0,5,0);
            webClient.DefaultRequestHeaders.Add("Authorization", authHeader);
            var stream = webClient.GetStreamAsync(url).Result;
            using (Stream file = File.OpenWrite(Paths.LocalDatabase)) {
                          stream.CopyTo(file);
            }
        }

堆栈跟踪

System.AggregateException: One or more errors occurred
  at System.Threading.Tasks.Task.Wait (Int32 millisecondsTimeout, CancellationToken cancellationToken) [0x00000] in <filename unknown>:0 
  at System.Threading.Tasks.Task.Wait () [0x00000] in <filename unknown>:0 
  at System.Threading.Tasks.Task`1[TResult].get_Result () [0x00000] in <filename unknown>:0 
  at DataFinch.Mobile.Core.Network.RemoteAPI.DownloadDatabase (Guid organizationId, Guid siteId) [0x00000] in <filename unknown>:0 
  at DataFinch.Mobile.Core.Services.Registration.RegistrationService.RegisterDeviceAndDownloadDatabase (System.String username, System.String password, Guid siteId) [0x00000] in <filename unknown>:0 

【问题讨论】:

  • 使用Task.Result调用异步重载和阻塞任务有什么意义?
  • 这已经在后台线程中,所以它需要在该线程中同步。
  • 是的,要么做完全异步,要么不做异步,否则你要求死锁。此外,如果您提供实际异常会很好,而不仅仅是 AggregateException(即迭代 InnerExceptions 属性),因为 AggregateExceptions 并没有真正提供太多信息。
  • 仅供参考,您仍然可以进行 async/await 调用并使其串行执行。
  • 聚合异常是:System.Threading.Tasks.TaskCanceledException:任务被取消,我认为是超时。

标签: c# asp.net-mvc xamarin task-parallel-library async-await


【解决方案1】:

这显然是由超时引起的 - 毕竟,堆栈跟踪表明异常发生在 Task.Wait(...) 中 - 这是由任务的 Result 属性在调用堆栈的更下方内部调用的。

因为这发生在客户端,所以您在服务器端无能为力。您可以尝试以某种方式使服务器更快。但我怀疑这是否真的有帮助,因为移动客户端可用的带宽仍然有限 - 更重要的是:这取决于每个客户的数据计划。

无论如何,由于您可以(而且您将)总是有带宽非常差的客户,因此文件大小通常对于定位移动客户端来说太大了。你所能做的就是为你的应用程序的下一个版本安排一个下载逻辑的重构,将你的下载分成更小的块,并让你的客户端代码尽可能好地处理这些类型的问题......

此外,在等待如此大的下载时阻塞整个线程(即使它是一个工作线程)也是一个坏主意(尤其是在没有可用带宽指示的移动客户端上)。这会导致线程很长时间没有响应。你也应该考虑改变这个逻辑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多