2016-08-16 2 views
1

Короче говоря, моя проблема в том, что я пытаюсь вернуть файл через контроллер, но иногда файл блокируется другим процессом, заставляя мой контроллер возвращать 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> 

Когда я посмотрел в окне просмотра событий , Я видел, что произошло исключение.

Процесс не может получить доступ к файлу '...' b потому что он используется другим процессом.

Я знаю, почему это, и как быстрое решение я сделал

 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! Очень странно, потому что я поймаю исключение и не перебрасываю его. Любая идея, что это за недостаток и как я могу это исправить?

EDIT:

трассировки стека указывает на линию

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

Этот ответ XML выглядит довольно универсальным. Может быть, другое исключение вызывает его? Каково точное исключение на этот раз и какая строка его выбрасывает? – David

+0

@ Давид Это тот же самый. Я собираюсь опубликовать трассировку стека выше. –

+0

Можете ли вы гарантировать, что вызывающий абонент не задержит время при вызове GetFile и, возможно, также гарантирует, что файл не будет заблокирован снова до начала загрузки? – ostati

ответ

0

Вместо быстрого решения, чтобы повторить попытку открытых операций с файлами, иногда позже я рекомендую искать первопричину, почему файл заблокирован процессом.

Следует попытаться изменить логику создания FileStream, чтобы не открывать поток исключительно. Следующая слегка расширенная логика создания снижает риск блокировок файлов.

Content = new StreamContent(
      new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
Смежные вопросы