I'm writing a string to a MemoryStream
I need to return the stream to the Controller Action so I can send it off as a file for download.
Normally, I wrap the Stream in a using statement, but, in this case, I need to return it. Does it still get Disposed after I return it? Or do I need to dispose it myself somehow?
//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; }
Controller Action that returns the file:
[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? }
Yes. It uses a using block around the stream, and that ensures that the resource will dispose.
To return a file stream, you can use a FileStreamResult. This lets you specify the stream, the MIME type, and some other options (like the file name). // the stream when the transfer is complete.
Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. Instead of calling this method, ensure that the stream is properly disposed.
According to source code here 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); } } }
Where FileStream
would have been the stream passed when you called
return File(stream, "application/octet-stream", "forums.csv");
Update.
Your question was originally tagged as Asp.Net MVC but the code looks like the more recent core framework.
Found it there as well though written differently it does the same thing technically.
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(); } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With