Tuesday, June 19, 2012

My Windows Azure Tangent

I lost a couple of days earlier this week when I decided to look into alternatives to us hosting our own web site in house, which is basically just a little DotNetNuke site these days, but many moons ago, well before the plethora of Content Management Systems that are available today, we had a very cool ASP (Classic!) site with CMS capabilities, before anyone knew what is was. (I'm talking 1998.)  Anyway, the rest is history, and remnant of that system remain, and we still rely on sharing one portion of the back end SQL database, with an in house app.

I looked into a few hosting solutions which provided DotNetNuke. They were all awesome and clearly selecting one of these very affordable hosting solutions is the way to go. Unfortunately, throwing our SQL database into the cloud, and running our ancient VB6 app against it, was going to impact performance too much at this stage. Suffice to say, some re-factoring (rewriting) of that old app is now on the agenda so we can get some stuff that ought not to be in house, out of house!

Along the way though I signed up for a three month trial of Windows Azure, only to discover when I logged in using my Windows Live ID, the same Windows Live ID that links to my MSDN Premium subscription, that I receive a Windows Azure account along with that subscription. Hadn't realised that, but how good is the sign up process that just realised it all for me.

Now I can build web sites / web servers etc on Azure. Looks like that might just be the way to go next. After a day or so of playing I'm quite excited about the prospects, but for now it's back to the day job before someone notices... but I have got a few things I'm busting to try out.

Unfortunately though, correct me if I'm wrong but it doesn't look exactly straight forward to move an existing SQL Server database onto SQL Azure. Certainly not a simple as a backup and restore, as I had originally hoped.

A generic error occurred in GDI+.

This week I've been focusing again on a utility I'm building to convert data from our old system to our new one - once that new one is in fact ready.

Anyway, this week I've been looking at some memory issues and the wonderful "generic error in GDI+" error I've been seeing crop up occasionally during the conversion process.

One part of the process, load l lot of small images out of a database, for writing straight back into a new database. The image data is read in as a byte array, from the byte array into a MemoryStream, which is in turn used to build an Image object, (Image being a property of one of the business entities) which is then saved. (The conversion process makes use of the business components, entities and data access classes already built to do this.)

So in trying to hunt down some out of memory error messages during this portion of the conversion, I"ve worked back through the code that manipulates the images to ensure objects are disposed of when they should be. I wrapped some portions of the code in using statements and noticed some small improvements. Until, that is, I wrapped a MemoryStream object in one particular innocuous looking private function in a using statement in order to ensure that stream object was disposed of quickly as it was called repetitively.

The job of that function was to take a byte array and give me back an Image.

Originally:


        protected System.Drawing.Image getImageFromByte(Byte[] img)
        {
            System.Drawing.Image returnValue = null;
 
            if (img == null)
                return null;

                System.IO.MemoryStream stream = new System.IO.MemoryStream(img);
                returnValue = System.Drawing.Image.FromStream(stream);
 
            return returnValue;
        }

Became this;

        protected System.Drawing.Image getImageFromByte(Byte[] img)
        {
            System.Drawing.Image returnValue = null;
 
            if (img == null)
                return null;
 
            using (System.IO.MemoryStream stream = new System.IO.MemoryStream(img))
            {
                returnValue = System.Drawing.Image.FromStream(stream);
            }
 
            return returnValue;
        }


After that small change, every call to access the image that was returned by this function, failed with a "Generic GDI+ error" exception.

Once again, Stackoverflow to the rescue:
http://stackoverflow.com/questions/3845456/loading-an-image-from-a-stream-without-keeping-the-stream-open


Turns out, the Image object keeps a reference to it's core Stream object for optimisation purposes, so that when it is disposed, before the image is, you're in a world of trouble.


This article helps explain why: http://support.microsoft.com/Default.aspx?id=814675

The answer? I chose the non-indexed method - it just seemed easier...

        protected System.Drawing.Image getImageFromByte(Byte[] img)
        {
            System.Drawing.Image returnValue = null;
 
            if (img == null)
                return null;
 
            using (System.IO.MemoryStream stream = new System.IO.MemoryStream(img))
            using (System.Drawing.Image imgFromStream = System.Drawing.Image.FromStream(stream))
            {
                // Image object requires the MemoryStream be kept open - work around, create a new non-indexed image
                
                // Set the newImage being created to the same size as the original image
                System.Drawing.Bitmap newImg = new System.Drawing.Bitmap(imgFromStream.Width, imgFromStream.Height);
 
                using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(newImg))
                {
                    // Draw the imgFromStream onto the newImg graphics object
                    g.DrawImage(imgFromStream, 0, 0);
                }
 
                returnValue = newImg;
            }
            
            return returnValue;
        }