为什么异常一直在这里冒泡

本文关键字:在这里 一直 异常 为什么 | 更新日期: 2023-09-27 18:02:35

简而言之,我的问题是我试图通过控制器返回文件,但有时文件被另一个进程锁定,导致我的控制器返回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>

当我查看事件查看器时,我看到有一个异常抛出

进程无法访问文件'…,因为它被另一个进程。

我知道这是为什么,作为一个快速的解决方案,我做了

        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()

为什么异常一直在这里冒泡

我建议寻找文件被进程锁定的根本原因,而不是稍后重试打开文件操作的快速修复。

改变FileStream的创建逻辑,使其不独占地打开流是值得尝试的。下面稍微扩展的创建逻辑降低了文件锁的风险。

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