views:

141

answers:

1

BACKGROUND:
MS Access 2007 added an attachment field type, where images can be stored.
I am building a website using ASP.Net and the .NET framework 4

So, without using Silverlight, what is the easiest way to retrieve the image from the Access database on the server, and use as source for an Image control?

As a simple example:
In an ESL website for children, clicking on a "A", would display an apple; "B" a bear, etc

NOTE: This is an A2007/A2010 attachment field, not a binary object

+5  A: 

You could read the image out of the database as a binary blob. This would be read out as a byte[] array. That byte[] could then be sent to the browser using a Response.BinaryWrite and a content-type of image/(type) - jpg/png/gif.

The call would look something like:

<img src="showmyimages.aspx?image=id" />

And the code would look a little like:

result = myWebService.GetImage(id);

if (result != null) && result.Length > 0
{
    Context.Response.ClearContent();
    Context.Response.ClearHeaders();
    Context.Response.ContentType = "image/gif";
    Context.Response.AddHeader("Content-Length", result.Length.ToString(System.Globalization.CultureInfo.CurrentCulture));
    Context.Response.AddHeader("content-disposition", String.Format("inline; filename={0}.gif", filename));
    Context.Response.BinaryWrite(result);
    Context.Response.End();
}

This disguises the filename of the image a little bit, but it allows the binary read directly from the database without having a permanent image on disk.

EDIT:

Everything I've read about the attachment field is that it stores as direct binary in the database just as it would if it were saving directly to a file. I haven't attempted to write any code to this effect, but it is conceivable that no conversion is necessary if the binary data can be fed into a StreamReader, possibly even making use of WebResponse.GetResponseStream()

EDIT:

I was able to implement a handler using the following code that actually pulled the binary data from the attachment field (which can be verified in the debugger), however there appears to be an encoding involved that is not built in. The key seems to be the select statement that retrieves fldImage.FileData.

public void ProcessRequest(HttpContext context)
        {

            string qry = "SELECT [Image], ID, [Images.Image.FileData] AS FileData, ";
            qry += "[Images.Image.FileName] AS FileName, [Images.Image.FileType] AS FileType";
            qry += " FROM Images WHERE (ID = 1)";
            string connect = @"Provider=Microsoft.ACE.OLEDB.12.0;Persist Security Info=False;Data Source=##PathToDB##\Database1.accdb";

            using (OleDbConnection conn = new OleDbConnection(connect))
            {
                if (context.Request.QueryString["id"] != null)
                {

                    OleDbCommand cmd = new OleDbCommand(qry, conn);
                    cmd.Parameters.AddWithValue("ID", context.Request.QueryString["id"]);
                    conn.Open();
                    using (OleDbDataReader rdr = cmd.ExecuteReader())
                    {
                        if (rdr.HasRows)
                        {
                            rdr.Read();
                            context.Response.ClearContent();
                            context.Response.ClearHeaders(); 
                            context.Response.ContentType = "image/" + rdr["FileType"];

                            byte[] result = Encoding.UTF8.GetBytes(rdr["FileData"].ToString());

                            context.Response.AddHeader("Content-Length",
                                result.Length.ToString(System.Globalization.CultureInfo.CurrentCulture)); 
                            context.Response.AddHeader("content-disposition", 
                                String.Format("attachment; filename={0}", rdr["FileName"]));
                            context.Response.BinaryWrite(result);
                            context.Response.End();
                        }
                    }
                }
            }

        }

There are also some methods that are located in the Microsoft Office Interop library described at the MSDN Access Blog that may be of use. They describe loading and saving files, but it looks as if they may also be able to perform the same actions directly to stream objects. The reference is Microsoft.Office.Interop.Access.Dao. When adding it, go to the COM tab and look for Microsoft Office 12.0 Access Database Engine Objects Library. I haven't tested this "straight to stream" theory.

Joel Etherton
+1 I only suggest to remove the Content-Length and let the filter fix it because there are some issues if you try to Compress aspx page.
Aristos
Makes sense, but the attachment returns from the database with a type of string, not the actual image byte[] itself
Noah
@Noah - with the blob data you may have to perform some measure of conversion to put it into the proper binary encoding. I don't recall what the conversion is (it's been a long time since I attempted it).
Joel Etherton
@Joel, It looks like attachment type stores it as an object, not a blob. I'll have to check if I can just cast it.
Noah
Is this suggestion accounting for the difference between and A2007/A2010 attachment field and legacy OLE fields?
David-W-Fenton
@David-W-Fenton - no it isn't. I quit developing Access dbs a long time ago, so I left it open-ended with respect to the specific data type and left it vague enough that in order to make it work it would have to be modified to make the binary string work right. However, the primary suggestion I was putting forth was more focused on the web delivery method of the image rather than the conversion from db to binary string. Good mention of the difference though.
Joel Etherton
+1 good answer but I would suggest using a handler instead of a page.
Mike
@Mike - I'd say that depends on the needs of the application. For common every day usage, I would totally agree that a handler cuts out a ton of the overhead by bypassing all of the IIS claptrap a web form generates.
Joel Etherton
@Mike/Joel -- Agreed, much better ways to display an image. However, the question that is bugging me is not what is the best way to display the image in a web page, rather how to get the object out of the attachment type field
Noah
@Noah - I've plugged away at this for a bit, and as it's written in the documentation, you should be able to able to select the binary data in your sql statement using `[fldImage.FileData] As FileData`. I've put forth several tests and I've been unable to get a valid image out, however. I see the binary data, and everything looks valid, but I have been unable to get the encoding right.
Joel Etherton
@Joel: Exactly! This is the problem that has bugged me for months! I was hoping to "bounty" would bring some more eyes to it.
Noah
@Noah - In reading the documentation, there isn't even anything on MSDN that indicates the attachment field is a good field type for this purpose. Typically they would have at least one example of this behavior. There is more to the encoding the field data than meets the eye.
Joel Etherton
@Joel, The documentation example shown, uses RecordSet2 to access the data, and that works just fine from C#, etc. However this is not available from ASP.NET (another driver for my frustration)
Noah
Noah - no this information is available, however the encoding is off. It's available through the Microsoft.Office.Interop namespace. The problem I found is that the data in the field can't be translated into a binary image of a valid format.
Joel Etherton
@Joel, can you summarize this into a new answer that I can accept
Noah
@Noah - added everything I could think of to add. Also put a link in and description of the DAO reference.
Joel Etherton