4

当我尝试将 png 保存到内存流时出现错误。在我的 ASP.NET 开发服务器上,一切正常,但是当我在 IIS7 下运行站点时 - 生成了一个错误。此外,当我尝试保存 jpg 格式时 - 一切都正确。在 IIS 中,我将 .NET Trusted Level 设置为 Full。但它仍然不起作用。我需要你的帮助。

private static Stream DrawBarChart(IEnumerable<Tuple<string, ulong, double>> data){
using (MemoryStream stream = new MemoryStream())
{
    var canvasWidth = PageSize.A4.Width;
    var canvasHeight = PageSize.A4.Height;

    using (
        System.Drawing.Image bitmap = new Bitmap((int) canvasWidth,
                                                 (int) canvasHeight))
    {
        using (var graphics = Graphics.FromImage(bitmap))
        {
            var penBlack1 = new Pen(Brushes.Black, 1);

            graphics.DrawLine(penBlack1, 0, 0, canvasWidth, 0);
            graphics.DrawLine(penBlack1, 0, 0, 0, canvasHeight);

            graphics.Save();
        }
        bitmap.Save(stream, ImageFormat.Png);

    stream.Flush();
    stream.Position = 0;

    return stream;
    }
}

}

4

1 回答 1

3

您的代码中至少有 2 个完全独立的问题导致其出现故障。

问题 #1:GDI+ 错误

这是一个反复出现的问题,在生态系统的各个地方不断涌现。我有它,我设法修复它,现在我不记得具体如何了。我试图复制您的问题,但未能收到失败消息。

我建议你检查这个线程:http ://forums.asp.net/t/624305.aspx/1 这里有些人很高兴地通过以下方式克服了这个问题:

  • 确保他们在处理其他绘图之前处理了所有的 Bitmap 实例
  • 有趣的一个):做一个GC.Collect()(可能在每次位图渲染之后)

这不是我想尝试帮助您回答的主要原因。看来你已经做了(你说你做了)我通常做的所有事情,以确保我不会最终陷入这种情况(安全、信任等)。此外,您自己进行的清理工作超出了需要(阅读我的答案时您会发现有点太多了)。

我发现您的代码有第二个问题,您可能不知道。通过在我自己的 VS 环境中简单地解决这个问题,我成功地渲染了位图(在 IIS 7 和 Express 以及 ASP 开发服务器中)。

很有可能通过在应用程序代码中重新组织一些东西,您将设法解决问题 #1。所以:请查看我对问题 #2 的看法。

问题#2:不能同时处理和返回流

您不能返回刚刚创建和处置的流,例如:

public static Stream SomeMethod() {
  using (MemoryStream stream = new MemoryStream()) {
    // write something to the stream
    return stream;
  }
}

我真的不明白那段代码在 ASP.NET 开发服务器中是如何工作的。我在这里要指出的问题是您的代码总是会抛出 ObjectDisposedException (无论您是将代码作为服务运行还是在交互式用户空间中运行):

无法访问已关闭的流

谁关闭了流?using语句的终止。

问题 #2 的可能解决方案

这个特定问题的快速解决方案(可能会占用比您预期的更多的内存)是让您的方法返回一个 byte[] 而不是一个流。

public static byte[] SomeMethod() {
  using (MemoryStream stream = new MemoryStream()) {

    // ... create bitmap and render things ...

    // write something to the stream
    bitmap.Save(stream, ImageFormat.Png);

    return stream.ToArray();
  }
}

允许我自己对您的应用程序需求做出假设,我会说这个其他解决方案可能会更好:

如果您希望将这些生成的图表图像以<img>标记返回到 Web 浏览器,并且您通过 ASP.NET 通用处理程序来完成此操作,那么您可以将 OutputStream 传递给当前 WebResponse您的绘图方法,而不是从中获取结果 byte[] (或 Stream)如下所示:

在 HTML 中:

<img src="path/Foo.ashx" alt="chart" ... etc ... />

在应用程序中:

public class Foo : IHttpHandler {
  public void ProcessRequest(HttpContext context) {

   context.Response.ContentType = "application/octet-stream";
   Stream alreadyExistingStream = context.Response.OutputStream;

   Etc.SomeMethod(stream);       
  }
}

public class Etc {

public static void SomeMethod(Stream stream) {
  // There used to be a using here that would create a stream
    // simply because the parameter name **stream** is the same as the former local var's name
    // the instructions that do the drawing of things 
    // + saving of the resulting Bitmap **to** the stream
    // keep on compiling without any problems

    // draw things to a bitmap
    // write the bitmap to the stream
    bitmap.Save(stream, ImageFormat.Png);

    // returning stuff is not needed anymore
  // This used to be the time and place where the stream would be disposed
  // and it's resources given back to the community
}

}
于 2013-02-23T18:16:40.980 回答