Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a MemoryStream get disposed of automatically when returning it as 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 am accustomed to using the 'using' statement in conjuction with MemoryStreams. Is this a scenario where the 'using' statement is not necessary? Or is it valid to call return inside of a 'using' statement?

EDIT:

For my purposes I have found that the introduction of a 'using' statement does NOT work (throws an ObjectDisposedException). Here's what I'm doing with it 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);
like image 387
Sean Anderson Avatar asked Jan 10 '12 17:01

Sean Anderson


People also ask

Does MemoryStream need to be disposed?

MemoryStream does not have any unmanaged resources to dispose, so you don't technically have to dispose of it. The effect of not disposing a MemoryStream is roughly the same thing as dropping a reference to a byte[] -- the GC will clean both up the same way.

How do I reuse MemoryStream?

You can re-use the MemoryStream by Setting the Position to 0 and the Length to 0. By setting the length to 0 you do not clear the existing buffer, it only resets the internal counters.

How do you save on MemoryStream?

Save MemoryStream to a String Steps follows.. StreamWriter sw = new StreamWriter(memoryStream); sw. WriteLine("Your string to Memoery"); This string is currently saved in the StreamWriters buffer.


3 Answers

Does a MemoryStream get disposed of automatically when returning it as an ActionResult?

Yes, MVC (at least version 3) will clean it up for you. You can take a look at 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 line using (FileStream) { will place the Stream in a using block, thus Disposing of it when it has written the contents to the Http Response.

You can also verify this behavior by creating a dummy stream 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 dispose it.

like image 184
vcsjones Avatar answered Oct 22 '22 12:10

vcsjones


Sean: Do NOT use 'using' as it will Dispose the object. Leaving MVC accessing a Disposed object. Hence the exception(server error) you experienced is certainly an ObjectDisposedException. The WriteFile function previously posted Disposes the object for you.

like image 39
Steven Licht Avatar answered Oct 22 '22 14:10

Steven Licht


A MemoryStream is not necessary in this situation. You can avoid it by creating a Custom ActionResult like this :

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);
    }
}
like image 2
Kalten Avatar answered Oct 22 '22 12:10

Kalten