繁体   English   中英

MultipartFormDataStreamProvider 和在上传后立即读取文件有时会失败

[英]MultipartFormDataStreamProvider and reading file immediately after its uploaded fails sometimes

我有一些从 SO 帖子和其他站点组装的 Web API 代码。 然而,任务的东西对我来说仍然是新的。 我正在尝试将上传的文件复制到新位置,但有时(并非所有时间)在尝试复制文件时出现异常。 该异常表明该文件正被另一个进程使用。 不过也不是每次都这样。 我想我需要将复制操作移到其他地方。 这是我的代码。 有什么建议么?

var provider = new MultipartFormDataStreamProvider(uploadroot);
                var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith<HttpResponseMessage>(t =>
                {
                    if (t.IsFaulted || t.IsCanceled)
                        throw new HttpResponseException(HttpStatusCode.InternalServerError);

                    var docConversionId = Guid.NewGuid().ToString("N");
                    var sourceFilePath = Path.Combine(uploadroot, provider.FileData.First().LocalFileName);
                    var destinationFilePath = Path.Combine(inboxroot, docConversionId);

                    File.Copy(sourceFilePath, destinationFilePath);

                    var response = new HttpResponseMessage(HttpStatusCode.OK);
                    response.Content = new StringContent(docConversionId);
                    //response.Content.Headers.Add("DocumentConversionId", docConversionId);
                    return response;
                });
                return task;

在使用 ReadAsMultipartAsync 后立即尝试读取/删除文件可能会遇到一个已知问题。

以下是与它相关的错误(您可以查看分辨率信息以了解有关其发生原因以及解决方法的更多详细信息):

https://aspnetwebstack.codeplex.com/workitem/176

由于 codeplex 中的原始讨论已死,因此我在此处粘贴了该问题最初于 2013 年关闭时的原始解释和解决方法:

我们正在关闭此问题,因为发现根本原因在框架代码中。 已针对外部合作伙伴团队打开了一个单独的错误,并将在那里跟踪此问题。

变更集: http : //aspnetwebstack.codeplex.com/SourceControl/changeset/changes/452b8e1dfa40

恢复我们使用 FileOptions.WriteThrough 的尝试修复,以确保它不是文件缓存和 FileStream 代码之间的竞争。 但是 WriteThrough 没有解决核心错误并导致性能下降。

对用户代码的影响是:如果您使用 MultipartFormDataContent 上传文件并使用 MultiPartDataStreamProvider 在服务器上读取它,则在 ReadAsMultipartAsync 完成后,服务器上的底层文件可能不会完全关闭。 有一个小窗口,其中本机代码可能仍在另一个线程上释放文件资源。

影响是在异步读取后立即对该文件执行的 File.Delete 或 File.OpenRead 可能会失败并显示 IOException(“文件正在被另一个进程使用”)。 我们在高负载情况下观察到大约 0.3% 的故障率。 唯一已知的解决方法是对这些操作进行 try/catch,如果发生 IOException 则延迟一小段时间,然后重试。 50 毫秒延迟通常有效,但建议允许多次重试。 这允许本机线程完成其资源的释放。 在我们的压力实验室中,这种捕获延迟和重试算法总是成功的。

我遇到了这个疯狂的问题,并发现它可以与await关键字一起使用。

await Request.Content.ReadAsMultipartAsync(streamProvider);

无需将任务保存在变量中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM