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