从操作返回文件时,流是否会被处置?

Does a Stream get Disposed when returning a File from an Action?

我正在将字符串写入 MemoryStream 我需要将流 return 发送到控制器操作,以便我可以将其作为文件发送以供下载。

通常,我将 Stream 包装在 using 语句中,但在这种情况下,我需要 return 它。在我 return 之后它仍然会被处置吗?还是我需要自己以某种方式处理它?

//inside CsvOutputFormatter
public Stream GetStream(object genericObject)
{
    var stream = new MemoryStream();
    var writer = new StreamWriter(stream, Encoding.UTF8);
    writer.Write(_stringWriter.ToString());
    writer.Flush();
    stream.Position = 0;
    return stream;
}

return文件的控制器操作:

[HttpGet]
[Route("/Discussion/Export")]
public IActionResult GetDataAsCsv()
{
    var forums = _discussionService.GetForums(_userHelper.UserId);

    var csvFormatter = new CsvOutputFormatter(new CsvFormatterOptions());

    var stream = csvFormatter.GetStream(forums);
    return File(stream, "application/octet-stream", "forums.csv");

    //is the stream Disposed here automatically?
}

根据这里的源代码aspnet/AspNetWebStack/blob/master/src/System.Web.Mvc/FileStreamResult.cs

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 (true)
        {
            int bytesRead = FileStream.Read(buffer, 0, BufferSize);
            if (bytesRead == 0)
            {
                // no more data
                break;
            }

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

其中 FileStream 是您调用

时传递的流
return File(stream, "application/octet-stream", "forums.csv");

更新。

您的问题最初被标记为 Asp.Net MVC,但代码看起来像是更新的核心框架。

在那里也找到了它,虽然写法不同,但它在技术上做同样的事情。

aspnet/AspNetCore/blob/master/src/Mvc/Mvc.Core/src/Infrastructure/FileResultExecutorBase.cs

protected static async Task WriteFileAsync(HttpContext context, Stream fileStream, RangeItemHeaderValue range, long rangeLength)
{
    var outputStream = context.Response.Body;
    using (fileStream)
    {
        try
        {
            if (range == null)
            {
                await StreamCopyOperation.CopyToAsync(fileStream, outputStream, count: null, bufferSize: BufferSize, cancel: context.RequestAborted);
            }
            else
            {
                fileStream.Seek(range.From.Value, SeekOrigin.Begin);
                await StreamCopyOperation.CopyToAsync(fileStream, outputStream, rangeLength, BufferSize, context.RequestAborted);
            }
        }
        catch (OperationCanceledException)
        {
            // Don't throw this exception, it's most likely caused by the client disconnecting.
            // However, if it was cancelled for any other reason we need to prevent empty responses.
            context.Abort();
        }
    }
}