In my years of web development, there's always been one sticky point - Images. Each time I being writing an application, I can't help but think - there must be a better way than this. I've found many different ways over the years, but none of really stuck out as "better". The problem really breaks down to - how do you work with dynamic images in a databound web application? In order to find the best solution for this, we need to break this question down into two smaller questions.
1) Do images belong in your database, or should they remain on your file system.
2) How do you dynamically display the image corresponding to the data on the page.
I'm sure you're used to hearing this by now - the answer to the first question is "it depends". Unless you have an easy way to insert and update images in your database, there's a bit of overhead you'll have to struggle with if you want to serve up images directly from a DBMS. For small quick applications I would generally recommend using the files system, and use known file names to link images to data. However, if you're working on a large scale solution, A direct database streaming solution is a good investment. Now, I'm not a SQL expert, so if any of you are - I'd love to hear the pros and cons of this from a SQL DBAdmin's perspective.
No matter what you decide, the first part to the solution will be the same - embed an Image into your page. We all know how to do this in a simple ASP.NET page, but what if you need to display images in a list using a Repeater or DataGrid with Templating capabilities? The Infragistics UltraWebGrid just like the Microsoft GridView has a "TemplateColumn" which can be used to customize the view of individual cells in that column. Simply add an asp:image tag inside of the template, and then use some declarative databinding to bind the ImageUrl property. Here's an example column for the WebGrid
<igtbl:TemplatedColumn BaseColumnName="PhotoUrl" IsBound="True" Key="PhotoUrl">
<RowLayoutColumnInfo OriginX="1" />
<RowLayoutColumnInfo OriginX="1" />
<asp:Image runat="server" ID="image1" ImageUrl="<%# Container.Value %>" />
Notice that the ImageUrl is being bound to the Container.Value, which is the value of the PhotoUrl field. This value can either point directly to an image url, or in my case I pointed it towards an HttpHandler. The PhotoUrl field is not an actual field in my table, but rather a virtual field that I create through my Sql Query. Here's an example of how I created mine:
SELECT FirstName, 'imgstrm.ashx?id=' + CAST(EmployeeID AS Varchar(16)) AS PhotoUrl, Photo, EmployeeID FROM Employees
In the query above, I'm pulling data out of the classic Northwind database, using the Employees table. Notice that I'm affixing 'imgstrm.ashx?id=' to the front of the string value. imgstrm.ashx is my HttpHandler, and I'm using ?id= to pass in a QueryString value along with the request. HttpHandlers are a great way to manage images because they can be used to write the image bits directly to the output stream, without the overhead of an ASPX page. In this example, the handler simply looks at the value of the id QyeryString parameter and writes the appropriate bytes to the OutputStream. If you're instead going with a file system solution, you can slightly modify the code in the HTTP handler to redirect the response to the actual ImageUrl. By pointing all of your requests through the handler, you can easily switch between a file system or an embedded database solution, without having to modify your code.
Streaming the bytes out is the easy part, simply grab your byte out of your database, and write it to the output stream of the response object. Don't forget to set the ContentType of the response to match your image format. And if you're using a .PNG format, you'll want to load the bytes into a memory stream before writing them to the OutputStream.
You can download the entire source for this project here. Note, this was built with NetAdvantage 2007 Volume 3. If you do not have NetAdvantage installed, simply replace the UltraWebGrid with a GridView or a Repeater, and remove the references from the web.config.