A common error occurred in GDI + when I save png to a MemoryStream in IIS7

I have an error when I try to save png to a memory stream. Everything works on my ASP.NET development server, but when I launch the site under IIS7, an error occurs. Also, when I try to save the jpg format - everything is correct too. In IIS, I have .NET Trusted Level to Full installed. But it still does not work. I need your help.

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
source share
1 answer

There are at least 2 completely independent problems in the code that cause it to crash.

Problem # 1: GDI + Error

This is a recurring problem that continues to arise throughout the ecosystem. I had it, I managed to fix it, now I don’t remember exactly how to do it. I tried to replicate your problem, and I was not able to get a failure.

I suggest you check this topic: http://forums.asp.net/t/624305.aspx/1 Here, some guys have successfully coped with the problem:

  • Making sure that they have placed all instances of Bitmap before executing other drawings.
  • ( interesting ): Executing GC.Collect () (possibly after each bitmap rendering)

This is not the main reason why I wanted to try and help you with the answer. It seems that you have already done (you say you did) everything that I usually do to make sure that I do not get into this situation (security, trust, etc.). Furthemore, you cleanse after yourself more than necessary (a little too much, as you learn when reading my answer).

I found that your code has a second problem that you probably don't suspect. Just solving this problem in my own VS environment, I successfully executed Bitmaps (in both IIS 7, Express, and ASP Development Server).

It is possible that by reorganizing things in your application code, you will be able to solve problem # 1. So: please check what I have to say about issue # 2.

Problem # 2: Threads cannot be deleted and returned at the same time

You cannot go and return the threads that you just created and are located , for example:

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

I really don't understand how this piece of code works on the ASP.NET Development Server. The problem I'm trying to point out here is that your code will always throw an ObjectDisposedException (regardless of whether you use the code as a service or in the user's interactive space):

Cannot access a closed stream

Who closes the stream? Completing an action with .

Possible solutions to problem # 2

A quick fix to this problem (which could use more memory than you predicted) would be to have your method return a byte [] instead of a stream.

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

Allowing myself to make assumptions about the needs of your applications, I would say that this other solution could be even better:

If , then you want to return these generated graphic images to <img> back to the web browser, and you do this using, say, ASP.NET common handlers, then you can pass the OutputStream of the current WebResponse method to , instead of taking the resulting byte [] (or stream) from , like this:

In HTML:

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

while in the application:

 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 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 resources given back to the community } } 
+3
source

Source: https://habr.com/ru/post/1441566/


All Articles