将MemoryStream作为ActionResult返回时,它是否会被自动处理?

时间:2012-01-10 17:50:46

标签: c# jquery asp.net-mvc using memorystream

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

我习惯于将“using”语句与MemoryStreams结合使用。这是不需要'使用'语句的情况吗?或者在'using'语句中调用return是否有效?

编辑:

出于我的目的,我发现引入'using'语句不起作用(抛出ObjectDisposedException)。这就是我在客户端做的事情:

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

4 个答案:

答案 0 :(得分:21)

  

将MemoryStream作为ActionResult返回时会自动处理掉吗?

是的,MVC(至少版本3)会为您清理它。您可以在WriteFile中使用FileStreamResult方法{/ 3}}:

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

using (FileStream) {会将Stream放入一个使用块中,从而在将内容写入Http响应时处理它。

您还可以通过创建执行此操作的虚拟流来验证此行为:

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

所以MVC 处理它。

答案 1 :(得分:2)

肖恩:不要使用'使用',因为它会处理对象。让MVC访问Disposed对象。因此,您遇到的异常(服务器错误)肯定是ObjectDisposedException。之前发布的WriteFile函数为您处理对象。

答案 2 :(得分:2)

在这种情况下不需要MemoryStream。您可以通过创建这样的Custom ActionResult来避免它:

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

答案 3 :(得分:-4)

以下是处理流的有效代码。如果包含在using块中,则会在返回时自动调用MemoryStream.Dispose()方法。

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

通过将对象放在try块中,然后在finally块中调用Dispose,可以获得相同的结果。实际上,根据MSDN文档,这是编译器如何翻译using语句。在try..finally块中,即使finally通过try退出,return也会一直执行。

编译器会将using块转换为以下内容:

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