为什么异常会一直冒泡到这里?

时间:2016-08-16 19:06:57

标签: c# asp.net .net asp.net-mvc

简而言之,我的问题是我试图通过控制器返回文件,但有时文件被另一个进程锁定,导致我的控制器返回null

我的控制器就像(这不是确切的,但它是等同的)

[HttpGet]
public IHttpActionResult GetFile(int fileid)
{
   string filepath = GetFilePathFromId(fileid); 
   return new FileDownload(filepath);
}

public class FileDownload : IHttpActionResult
{
     private string FilePath { get; set; }
     public FileDownload(string filePath)
     {
         FilePath = filepath;
     }
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StreamContent(new FileStream(FilePath, FileMode.Open))
        };

        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = Path.GetFileName(FilePath)
        };

        return Task.FromResult(response);
    }
}

这有时会返回一个通用的XML 错误

<Error><Message>An error has occurred.</Message></Error>

当我查看事件查看器时,我看到引发了异常

  

该过程无法访问文件&#39; ...&#39;因为它正被使用   另一个过程。

我知道为什么会这样,并且作为我做的快速解决方案

        IHttpActionResult file = null;
        var fiveSecondsLater = DateTime.Now.AddSeconds(5);
        while(DateTime.Now < fiveSecondsLater)
        {
            try
            {
                file = new FileDownload(filepath);
                break;
            }
            catch 
            {
                Thread.Sleep(500);
            }
        }
        return file ?? Content(HttpStatusCode.InternalServerError, "Could not access file."); 

然而,奇怪的是,这仍然导致XML错误!非常奇怪,因为我抓住了异常并且没有重新抛出异常。知道这里的缺陷是什么以及如何解决它?

编辑:

将跟踪点堆叠到行

HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)

作为问题之一。堆栈跟踪就像

at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode)
   at ....FileDownload.ExecuteAsync(CancellationToken cancellationToken) in ...:line 81
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()

1 个答案:

答案 0 :(得分:0)

有时候我建议您搜索文件被进程锁定的根本原因,而不是快速修复重试打开文件的操作。

值得尝试更改FileStream创建逻辑,而不是专门打开流。以下稍微扩展的创建逻辑可降低文件锁定的风险。

Content = new StreamContent(
             new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))