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