Does a MemoryStream delete automatically when I return it to an ActionResult?

public ActionResult CustomChart(int reportID) { Chart chart = new Chart(); // Save the chart to a MemoryStream var imgStream = new MemoryStream(); chart.SaveImage(imgStream); imgStream.Seek(0, SeekOrigin.Begin); // Return the contents of the Stream to the client return File(imgStream, "image/png"); } 

I'm used to using the 'using' statement in conjunction with MemoryStreams. Is this a scenario where the statement β€œusing” is not necessary? Or is this really the case to cause a return inside the 'using' statement?

EDIT:

For my purposes, I found that introducing the 'using' statement DOES NOT work (throws an ObjectDisposedException). Here is what I do with it on the client side:

 $('#ReportTest').bind('load', function () { $('#LoadingPanel').hide(); $(this).unbind('load'); }).bind('error', function () { $('#LoadingPanel').hide(); $(this).unbind('error'); }).attr('src', '../../Chart/CustomChart?ReportID=' + settings.id); 
+7
source share
4 answers

Does a MemoryStream resolve automatically when it returns as an ActionResult?

Yes, MVC (at least version 3) will clear it for you. You can see the source of the WriteFile method in FileStreamResult :

 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); } } } 

The using (FileStream) { will put the Stream in the use block, so Disposing from it when he wrote the content in the Http Response.

You can also test this behavior by creating a dummy thread that does this:

 public class DummyStream : MemoryStream { protected override void Dispose(bool disposing) { Trace.WriteLine("Do I get disposed?"); base.Dispose(disposing); } } 

So MVC will recycle it.

+19
source

Sean: DO NOT use "use" as it will destroy the object. Leave MVC access to the Disposed object. Therefore, the exception (server error) that you experienced is, of course, an ObjectDisposedException. The WriteFile function was previously added. Exposes an object for you.

+2
source

In this situation, a MemoryStream is not required. You can avoid this by creating a Custom ActionResult as follows:

 public class ChartResult : ActionResult { private Chart _chart; public ChartResult(Chart chart) { if (chart == null) throw new ArgumentNullException("chart"); _chart = chart; } public override void ExecuteResult(ControllerContext context) { if (context == null) throw new ArgumentNullException("context"); HttpResponseBase response = context.HttpContext.Response; response.ContentType = "image/png"; response.BufferOutput = false; _chart.ImageType = ChartImageType.Png; _chart.SaveImage(response.OutputStream); } } 
+2
source

The following is a valid code that the stream transmits. If it is enclosed in a using block, the MemoryStream.Dispose() method will be called automatically upon return.

 public ActionResult CustomChart(int reportID) { Chart chart = new Chart(); using (var imgStream = new MemoryStream()) { chart.SaveImage(imgStream); imgStream.Seek(0, SeekOrigin.Begin); return File(imgStream, "image/png"); } } 

You can achieve the same result by placing an object inside a try block, and then calling Dispose on the finally block. In fact, according to the MSDN documentation, this is how the using statement is translated by the compiler. And in the try..finally finally block will always be executed, even if try exits via return .

The compiler will translate the using block to the following:

 MemoryStream imgStream = new MemoryStream(); try { chart.SaveImage(imgStream); imgStream.Seek(0, SeekOrigin.Begin); return File(imgStream, "image/png"); } finally { if (imgStream != null) ((IDisposable)imgStream).Dispose(); } 
-3
source

All Articles