FileStreamResult - 该进程无法访问该文件,因为它正被另一个进程使用

FileStreamResult - The process cannot access the file, because it is being used by another process

ASP.NET 核心

MVC 控制器 - 使用 FileStream 从服务器存储下载文件并返回 FileStreamResult

public IActionResult Download(string path, string fileName)
{
    var fileStream = System.IO.File.OpenRead(path);

    return File(fileStream, "application/force-download", fileName);
}

一切正常,但是一旦用户在下载完成前取消下载,控制器中的其他操作使用此文件(删除文件,重命名file) 不起作用,因为:进程无法访问该文件,因为它正被另一个进程使用

FileStream 在文件下载完成后自动处理,但由于某些原因,当用户手动终止下载时它并没有终止。

我必须重新启动 Web 应用程序 => 使用该文件的程序是 IISExpress

如果用户手动结束下载,有人知道如何处理流吗?

编辑:

FileStream stream = null;
try
{
    using (stream = System.IO.File.OpenRead(path))
    {
        return File(stream, "application/force-download", fileName);
    }
}

我试图在返回 FileStreamResult 后结束 Stream 的代码,我知道它不能工作,因为在 return File (stream, contentType, fileName) 之后它立即跳转到块 finally 并且 stream 关​​闭,因此下载没有开始,因为 stream 已关闭

FileStreamResultclass的source好像不支持取消。 如果需要,您需要自己实施。例如。 (not-tested,纯属想象)

using System.IO;

namespace System.Web.Mvc
{
    public class CancellableFileStreamResult : FileResult
    {
        // default buffer size as defined in BufferedStream type
        private const int BufferSize = 0x1000;

        private readonly CancellationToken _cancellationToken;

        public CancellableFileStreamResult(Stream fileStream, string contentType,
            CancellationToken cancellationToken)
            : base(contentType)
        {
            if (fileStream == null)
            {
                throw new ArgumentNullException("fileStream");
            }

            FileStream = fileStream;
            _cancellationToken = cancellationToken;
        }

        public Stream FileStream { get; private set; }

        protected override void WriteFile(HttpResponseBase response)
        {
            // grab chunks of data and write to the output stream
            Stream outputStream = response.OutputStream;
            using (FileStream)
            {
                byte[] buffer = new byte[BufferSize];

                while (!_cancellationToken.IsCancellationRequested)
                {
                    int bytesRead = FileStream.Read(buffer, 0, BufferSize);
                    if (bytesRead == 0)
                    {
                        // no more data
                        break;
                    }

                    outputStream.Write(buffer, 0, bytesRead);
                }
            }
        }
    }
}

你可以像这样使用它

public IActionResult Download(string path, string fileName, CancellationToken cancellationToken)
{
    var fileStream = System.IO.File.OpenRead(path);
    var result = new CancellableFileStreamResult(
        fileStream, "application/force-download", cancellationToken);
    result.FileDownloadName = fileName;
    return result;
}

再说一次,我这不是测试,只是想象。 可能这不行,因为动作已经结束,不能再取消了。

编辑: 上述回答“想象”为 ASP.net 框架。 ASP.net core有一个完全不同的底层框架:在.net core中,action由and executor处理,如the source. That will eventually call WriteFileAsync in the FileResultHelper所示。在那里您可以看到 StreamCopyOperation 是使用 cancellationToken context.RequestAborted 调用的。 IE。 .net Core 中取消了。

最大的问题是:为什么在您的情况下请求没有中止。