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