Bitmap ctor error

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

We are experiencing intermittent errors when rendering images on some of our
pages in an asp.net web application. The errors all boil down to the
Bitmap..ctor() and are Invalid Parameter errors. The ctor in question only
accepts int32 parameters??. The very strange part is that after a reboot of
our server, displaying the same image works fine. Is there some bug in .Net
1.1 that I should be aware of? The fact that the problem goes away after a
reboot makes me believe this may be something in GDI? This has happened to us
on several occasions at several locations since upgrading our customers to
..NET 1.1. I've also seen a lot of postings on the boards regarding this, but
nothing concerning a possible .net bug.
Thanks,
Brandon
 
Brandon said:
We are experiencing intermittent errors when rendering images on some of
our
pages in an asp.net web application. The errors all boil down to the
Bitmap..ctor() and are Invalid Parameter errors. The ctor in question only
accepts int32 parameters??. The very strange part is that after a reboot
of
our server, displaying the same image works fine. Is there some bug in
.Net
1.1 that I should be aware of? The fact that the problem goes away after a
reboot makes me believe this may be something in GDI? This has happened to
us
on several occasions at several locations since upgrading our customers to
.NET 1.1. I've also seen a lot of postings on the boards regarding this,
but
nothing concerning a possible .net bug.
Thanks,
Brandon

Unfortunately MS failed to put following notice in the v1.x System.Drawing
documentation, but at least now they did in the only documentation.

http://msdn2.microsoft.com/en-us/library/system.drawing

Caution
Classes within the System.Drawing namespace are not supported for use
within a Windows or ASP.NET service. Attempting to use these classes from
within one of these application types may produce unexpected problems, such
as diminished service performance and run-time exceptions.




Willy.
 
Willy said:
Unfortunately MS failed to put following notice in the v1.x
System.Drawing documentation, but at least now they did in the only
documentation.
http://msdn2.microsoft.com/en-us/library/system.drawing

Caution
Classes within the System.Drawing namespace are not supported
for use within a Windows or ASP.NET service. Attempting to use these
classes from within one of these application types may produce
unexpected problems, such as diminished service performance and
run-time exceptions.

Do you know why?

I can understand that IIS does not run under the interactive user
account, but even so, the account it uses still has a desktop (it has to
have an NT window station object and an NT desktop object). Even if
there is some weirdness involved with running under a non-interactive
user desktop, a Bitmap object should not be affected unless it is
actually rendered in a device context. Other than rendering, a bitmap is
merely an array of bits and bitmap manipulations are just manipulations
of those bits. That manipulation should not be dependent upon the window
station where the code is running.

I have always felt that WinForms is a port from the unmanaged Visual
Basic runtime, and this seems to be yet another piece of evidence to
support my point of view.

Richard
 
Richard Grimes said:
Do you know why?

I think so :-).
I can understand that IIS does not run under the interactive user account,
but even so, the account it uses still has a desktop (it has to have an NT
window station object and an NT desktop object). Even if there is some
weirdness involved with running under a non-interactive user desktop, a
Bitmap object should not be affected unless it is actually rendered in a
device context. Other than rendering, a bitmap is merely an array of bits
and bitmap manipulations are just manipulations of those bits. That
manipulation should not be dependent upon the window station where the
code is running.

Agreed. but manipulating Bitmaps in Web applications is something you should
consider with care anyway, large or a large number of bitmaps may consume
extreme large chunks of (unmanaged) memory, memory you might need badly in
your web application anyway.

I have always felt that WinForms is a port from the unmanaged Visual Basic
runtime, and this seems to be yet another piece of evidence to support my
point of view.

Well, actually it's the System.Drawing namespace (wrapping GDI+) which is
not supported in server contexts (just like GDI+). System.Drawing classes
are just tiny GDI+ wrappers (gdiplus.dll), some of the methods do not
contain any managed code, for instance the Bitmap .ctors directly call one
of the GdipCreateBitmapFromxxxx (gdiplus.dll) overloads which doesn't need a
Graphics object or a DC, but most other methods (lets say gdi+) do depends
on a valid DC. Gues GDI+ is not supported/tested in multi-threaded contexts
either.
As far as I now WinForms was ported from their VJ++ WFC.


Willy.
 
Willy,
Thanks for the link and the info. Any suggestions on how to solve our
problem? We have bitmaps all throughout our web services. We retrieve binary
fields from an SQL Server db and use the bitmap object as an intermediary
between the db and the http stream. This web app is an image viewer, so it's
a VERY integral part of our application.
Thanks again for the info.
-Brandon
 
Willy said:
I think so :-).

I am listening... :-)
Agreed. but manipulating Bitmaps in Web applications is something you
should consider with care anyway, large or a large number of bitmaps
may consume extreme large chunks of (unmanaged) memory, memory you
might need badly in your web application anyway.

Well, perhaps. But its not a reason to issue such a warning. There are
plenty of other things that you can do which will consume large amounts
of memory. Are there similar warnings?

I don't think it is a general warning about memory usage. I think it
must go deeper than that. After all, we have all heard of Microsoft's
universal fix it mantra of 'add more memory to your machine' ;-)
some of the methods do not contain any managed code, for instance the
Bitmap .ctors directly call one of the GdipCreateBitmapFromxxxx
(gdiplus.dll) overloads which doesn't need a Graphics object or a DC,

Yup, and you can call GDI+ with unmanaged C++... I think I wrote an
article for my column in (the now defunct) Windows Developer Magazine
about that said:
but most other methods (lets say gdi+) do depends on a valid DC. Gues
GDI+ is not supported/tested in multi-threaded contexts either.

Maybe.

However, I see distinct advantages to being able to generate bitmaps on
the fly in a web application.
As far as I now WinForms was ported from their VJ++ WFC.

*ported* ;-)

Richard
 
Willy,
Thanks for the link and the info. Any suggestions on how to solve our
problem? We have bitmaps all throughout our web services. We retrieve binary
fields from an SQL Server db and use the bitmap object as an intermediary
between the db and the http stream. This web app is an image viewer, so it's
a VERY integral part of our application.
Thanks again for the info.
-Brandon
http://msdn2.microsoft.com/en-us/library/system.drawing


NET Framework Class Library
System.Drawing Namespace

Caution
Classes within the System.Drawing namespace are not supported for use
within a Windows or ASP.NET service. Attempting to use these classes
from within one of these application types may produce unexpected
problems, such as diminished service performance and run-time
exceptions.
[unquote]

It is truely remarkable that Microsoft no longer supports
System.Drawing in aspnet. It shows that all the talk about
multi-tiered applications is after all only marketing blubber.

Because, you see, if I have a 3-tier app, and my middle tier (business
layer) creates a bitmap, then I should be free to use a winforms front
end or a browser front end or a web service front end to present my
bitmap to the outside world. That's the essence of the three-tier
model, namely that my middle tier is INDEPENDENT of my front ends. I
know that there could be a problem with device contexts, but that is
not my problem, but Microsoft's.

Now Microsoft has introduced a dependency that makes my middle tier
dependent on the kind of front end (presentation layer) that I want to
use. Awful.

The worst thing is that I happen to know for a fact that most current
day browsers ARE capable of presenting bitmaps, jpegs, gifs on the
user's screen.
But now we learn that aspnet should be considered a text-only
interface to the world wide web. Some advancement.

Now the nitpicking boys COULD argue that you can still use bitmaps in
aspnet, by putting them in separate directories and using a src="url"
in your img tags. And you COULD create those bitmaps with separate
nonmanaged programs. Oh well. So we cannot use aspnet to do the work
we need to do, and present pictures in a browser. Perhaps we should
dump aspnet.

What is really going on is of course that the system has become too
complicated, that bugs abound everywhere and that they at Microsoft
don't have a clue where to find the solution to the problems that they
have created themselves. So they sell cars and tell their customers
that "driving with this superb Microsoft car is not supported".

---------

Now for a solution of some kind.

One of the nasty problems with managed Bitmap-objects is that they
keep their file handle open. You read your bitmap from file into
memory and you think that you can close your file afterwards, because
everything is now in memory. Not so. The bitmap file needs to be kept
open, because as a kind of efficiency measure it DOESN'T read all of
the bitmap pixels and colour info into memory when you ask it to read
everything into memory. In other words: it uses lazy load.

The same happens when you read your bitmap from a MemoryStream object
that gets its data from a byte array out of a blob field in SQL
Server. For example:

// the args are defined elsewhere:
msData = new MemoryStream(blob, ofsData, m_DataLen);
img = Image.FromStream(msData);
// following line is dangerous but necessary:
//msData.Close();
return img;

This works well, BUT the stream is not closed and although it's only a
memorystream I have noticed that rt exceptions can occur in due time.
So you should close the memorystream by removing the comments //.

But now the image object cannot use lazy load anymore, because it
hasn't access to the underlying data. This is a problem if you want to
save the returned image to file. E.g. in your main program you do:

img.Save(filename); //won't work

Now you get a System.Runtime.Interopservices.ExternalException "A
generic error occurred in GDI+".

Oh well, a generic message for a generic error.

This not having access to the underlying data could be a problem in
other circumstances too. In other words: the underlying stream needs
to remain open and it needs to be closed. Pick your choice.

What works for me is the following ashx:

/*
IHttpHandler voor het laden van een plaatje uit Pubs db
gebruik:
<img src=PubsImageHandler.ashx?id=pub_id /> [id=char(4)]
of:
<img src=<%# "PubsImageHandler.ashx?id=" +
DataBinder.Eval(Container.DataItem, "pub_id") %> />
*/

using System;
using System.Web;
using System.Data;
using System.Data.SqlClient;

public class PubsImageHandler : IHttpHandler
{
private const string ccCon = "Data Source=(local);Initial
Catalog=Pubs;Integrated Security=SSPI";
private const string ccSqlPub_info = "Select logo from
pub_info where pub_id = '{0}'";

public bool IsReusable
{
get {
return true;
}
}

public void ProcessRequest(HttpContext ctx)
{
SqlConnection cn = null;
SqlCommand cm = null;
string id = "";
byte[] buff = null;

id = ctx.Request.QueryString["id"];
if ( id.Length == 0 )
return;

try {
cn = new SqlConnection(ccCon);
cm = new
SqlCommand(string.Format(ccSqlPub_info, id), cn);
cn.Open();
buff = (byte[])cm.ExecuteScalar();
if ( buff.Length > 0 ) {
ctx.Response.ContentType = "image/*";
ctx.Response.BinaryWrite(buff);
}
}
catch (Exception) {
}
finally {
if ( cn != null )
cn.Close();
}
}
} //class PubsImageHandler

So I'm not using a Bitmap or Image class at all.

If you really want to send a bitmap or image back to the browser with
img.Save(outputstream) and the like, instead of sending the bytes
themselves, then perhaps the best way to go forward is to keep the
underlying file or stream open after creating and saving the image,
and close the file or stream in the page-unload event. This event
takes place when the page is already sent to the browser, so all code
that wants to do something with the img should be finished by that
time.

Perhaps the ashx httphandler runs on another thread, as the browser
retrieves the images separately. In that case you should use a
synchronization object and see if that works. I haven't tested this.

Bob Powell has some nice info on these problems with bitmaps:

http://www.bobpowell.net/imagefileconvert.htm

===========

By the way, this is a perfect example of the demise of object
orientation in general. In a few years we will learn that OO is not
only synonymous to bloated, hysterically complex design, inefficient
programming practices, untractable bugs, low performance, unsolvable
incompatibility issues and utter lack of code reuse, but also that it
defies one of the fundamental rules of Structured Programming:

"A function should have no hidden side effects."

That is, the inner workings of function A should NEVER affect the
behaviour of another function B.

The dotnet framework is like every framework riddled with "internal
optimizations" that affect the behaviour of classes in totally
different and seemingly unrelated parts of the framework. So there is
a deep hidden coupling between classes that should have only a very
loose, explicit coupling.

Ernesto.

"You don't have to learn science if you don't feel
like it. So you can forget the whole business if
it is too much mental strain, which it usually is."

Richard Feynman
 
Ernesto,
Thanks for the reply. I had to move to another project temporarily, so my
response is delayed, but thanks for your input. I came to the same conclusion
as you that my Bitmap objects in my middle tier needed to be done away with.
I too find this quite disturbing, especially since I never pass that object
back to my front end ... only the data within the object. My problem with
this approach is that we capture our images using third party software which
captures everything as grayscale tiff files, which is how they are stored.
So, I need to make a conversion on the data in order to present it in the
browser. I'm currently looking for a lightweight conversion class that I can
use for this rather than using the System.Drawing namespace.
-Brandon

Ernst Raedecker said:
Willy,
Thanks for the link and the info. Any suggestions on how to solve our
problem? We have bitmaps all throughout our web services. We retrieve binary
fields from an SQL Server db and use the bitmap object as an intermediary
between the db and the http stream. This web app is an image viewer, so it's
a VERY integral part of our application.
Thanks again for the info.
-Brandon
http://msdn2.microsoft.com/en-us/library/system.drawing


NET Framework Class Library
System.Drawing Namespace

Caution
Classes within the System.Drawing namespace are not supported for use
within a Windows or ASP.NET service. Attempting to use these classes
from within one of these application types may produce unexpected
problems, such as diminished service performance and run-time
exceptions.
[unquote]

It is truely remarkable that Microsoft no longer supports
System.Drawing in aspnet. It shows that all the talk about
multi-tiered applications is after all only marketing blubber.

Because, you see, if I have a 3-tier app, and my middle tier (business
layer) creates a bitmap, then I should be free to use a winforms front
end or a browser front end or a web service front end to present my
bitmap to the outside world. That's the essence of the three-tier
model, namely that my middle tier is INDEPENDENT of my front ends. I
know that there could be a problem with device contexts, but that is
not my problem, but Microsoft's.

Now Microsoft has introduced a dependency that makes my middle tier
dependent on the kind of front end (presentation layer) that I want to
use. Awful.

The worst thing is that I happen to know for a fact that most current
day browsers ARE capable of presenting bitmaps, jpegs, gifs on the
user's screen.
But now we learn that aspnet should be considered a text-only
interface to the world wide web. Some advancement.

Now the nitpicking boys COULD argue that you can still use bitmaps in
aspnet, by putting them in separate directories and using a src="url"
in your img tags. And you COULD create those bitmaps with separate
nonmanaged programs. Oh well. So we cannot use aspnet to do the work
we need to do, and present pictures in a browser. Perhaps we should
dump aspnet.

What is really going on is of course that the system has become too
complicated, that bugs abound everywhere and that they at Microsoft
don't have a clue where to find the solution to the problems that they
have created themselves. So they sell cars and tell their customers
that "driving with this superb Microsoft car is not supported".

---------

Now for a solution of some kind.

One of the nasty problems with managed Bitmap-objects is that they
keep their file handle open. You read your bitmap from file into
memory and you think that you can close your file afterwards, because
everything is now in memory. Not so. The bitmap file needs to be kept
open, because as a kind of efficiency measure it DOESN'T read all of
the bitmap pixels and colour info into memory when you ask it to read
everything into memory. In other words: it uses lazy load.

The same happens when you read your bitmap from a MemoryStream object
that gets its data from a byte array out of a blob field in SQL
Server. For example:

// the args are defined elsewhere:
msData = new MemoryStream(blob, ofsData, m_DataLen);
img = Image.FromStream(msData);
// following line is dangerous but necessary:
//msData.Close();
return img;

This works well, BUT the stream is not closed and although it's only a
memorystream I have noticed that rt exceptions can occur in due time.
So you should close the memorystream by removing the comments //.

But now the image object cannot use lazy load anymore, because it
hasn't access to the underlying data. This is a problem if you want to
save the returned image to file. E.g. in your main program you do:

img.Save(filename); //won't work

Now you get a System.Runtime.Interopservices.ExternalException "A
generic error occurred in GDI+".

Oh well, a generic message for a generic error.

This not having access to the underlying data could be a problem in
other circumstances too. In other words: the underlying stream needs
to remain open and it needs to be closed. Pick your choice.

What works for me is the following ashx:

/*
IHttpHandler voor het laden van een plaatje uit Pubs db
gebruik:
<img src=PubsImageHandler.ashx?id=pub_id /> [id=char(4)]
of:
<img src=<%# "PubsImageHandler.ashx?id=" +
DataBinder.Eval(Container.DataItem, "pub_id") %> />
*/

using System;
using System.Web;
using System.Data;
using System.Data.SqlClient;

public class PubsImageHandler : IHttpHandler
{
private const string ccCon = "Data Source=(local);Initial
Catalog=Pubs;Integrated Security=SSPI";
private const string ccSqlPub_info = "Select logo from
pub_info where pub_id = '{0}'";

public bool IsReusable
{
get {
return true;
}
}

public void ProcessRequest(HttpContext ctx)
{
SqlConnection cn = null;
SqlCommand cm = null;
string id = "";
byte[] buff = null;

id = ctx.Request.QueryString["id"];
if ( id.Length == 0 )
return;

try {
cn = new SqlConnection(ccCon);
cm = new
SqlCommand(string.Format(ccSqlPub_info, id), cn);
cn.Open();
buff = (byte[])cm.ExecuteScalar();
if ( buff.Length > 0 ) {
ctx.Response.ContentType = "image/*";
ctx.Response.BinaryWrite(buff);
}
}
catch (Exception) {
}
finally {
if ( cn != null )
cn.Close();
}
}
} //class PubsImageHandler

So I'm not using a Bitmap or Image class at all.

If you really want to send a bitmap or image back to the browser with
img.Save(outputstream) and the like, instead of sending the bytes
themselves, then perhaps the best way to go forward is to keep the
underlying file or stream open after creating and saving the image,
and close the file or stream in the page-unload event. This event
takes place when the page is already sent to the browser, so all code
that wants to do something with the img should be finished by that
time.

Perhaps the ashx httphandler runs on another thread, as the browser
retrieves the images separately. In that case you should use a
synchronization object and see if that works. I haven't tested this.

Bob Powell has some nice info on these problems with bitmaps:

http://www.bobpowell.net/imagefileconvert.htm

===========

By the way, this is a perfect example of the demise of object
orientation in general. In a few years we will learn that OO is not
only synonymous to bloated, hysterically complex design, inefficient
programming practices, untractable bugs, low performance, unsolvable
incompatibility issues and utter lack of code reuse, but also that it
defies one of the fundamental rules of Structured Programming:

"A function should have no hidden side effects."

That is, the inner workings of function A should NEVER affect the
behaviour of another function B.

The dotnet framework is like every framework riddled with "internal
optimizations" that affect the behaviour of classes in totally
different and seemingly unrelated parts of the framework. So there is
a deep hidden coupling between classes that should have only a very
loose, explicit coupling.

Ernesto.

"You don't have to learn science if you don't feel
like it. So you can forget the whole business if
it is too much mental strain, which it usually is."

Richard Feynman
 
Back
Top