Playing with Images in ASP.NET 3.5 AJAX Applications - Accessing Images from a SQL Server Database
(Page 5 of 5 )
As is indicated above, images in web applications can also be persisted in backend databases. However, there are drastic disputes about storing image data in databases. Anyway, let's first see a sample that shows how to use Microsoft SQL Server databases to access image data.
First, we will construct an example to grab images from a SQL Server database and render them on the web page.
Right click the above sample project and add an AJAX web form named DatabaseMode.aspx. In this application, the newest SQL Server sample database AdventureWorks_Data.mdf is required, in which we will work with the table ProductPhoto that provides two image fields (ThumbNailPhoto and LargePhoto, both of type varbinary) for us to access. The following Figure 3 shows one of the running-time snapshots. When the user selects a PhotoId from the ListBox at the upper left corner and clicks the 'View Product Picture' button, the corresponding product thumbnail will be rendered on the right side in the AJAX way.
Figure 3-the running-time snapshot for sample 3

Now, you can gradually find out the key how-tos, as follows. First, let's look at the page-related HTML elements design:
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server" />
</div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<table><tr>
<td valign="top">
<asp:Label ID="Label1" runat="server" Text="Please Select Product PhotoId:"></asp:Label>
<br />
<asp:DropDownList ID="prductList" runat="server"
DataSourceID="SqlDataSource1"
DataTextField="ProductPhotoID"
DataValueField="ProductPhotoID" />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click"
Text="View Product Picture" BorderColor="#3333FF"
/>
</td>
<td valign="top">
<asp:Image ID="Image1" runat="server" Height="160px" Width="307px" />
</td>
</tr>
</table>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:myAdventureWorks %>"
SelectCommand="SELECT [ProductPhotoID] FROM Production.ProductPhoto" >
</asp:SqlDataSource>
</form>
In this AJAX page, we used an ASP.NET AJAX server side control named UpdatePanel to enclose the <table/>, inside of which lie the ListBox control and an Image control for rendering images. Moreover, as a typical ASP.NET implementation, we introduced the SqlDataSource component to facilitate setting up bridges between the presentation tier and the backend storage.
Note in the SelectCommand property of the SqlDataSource control we have not 'Selected' the ThumbNailPhoto field and attached it to the Image control. In fact, we would achieve nothing (no images appear on the page) even if we did. Therefore, to render images in this database-related solution, we will have to fall back on another technique-the HTTP handler. The following gives the usage of the handler in this sample:
protected void Button1_Click(object sender, EventArgs e)
{
string url = String.Format("DatabaseImageHandler.ashx?PhotoID={0}", prductList.SelectedValue);
//string url = String.Format("ImageHandler.axd?PhotoID={0}", prductList.SelectedValue); //mentioned later
Image1.ImageUrl = url;
}
So when the user clicks the 'View Product Picture' button the DatabaseImageHandler.ashx is invoked to transform and transport data to the ImageUrl property of the Image1 control.
To write the above handler, right click the project and add a 'Generic Handler' named DatabaseImageHandler.ashx. As for the .ashx HTTP handler, since ASP.NET has provided a built-in item to the IIS meta database, we do not need to add a new <httphandler> within the web.config file and encapsulate the handler into an independent assembly. So now things are simple for us; we just need to write the .ashx HTTP handler, as follows:
public class DatabaseImageHandler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
// Ensure the URL contains an ID argument being a number
int id = -1;
bool result = Int32.TryParse(context.Request.QueryString["PhotoID"], out id);
if (!result)
{
context.Response.End();
}
string connString = ConfigurationManager.ConnectionStrings["myAdventureWorks"].ConnectionString;
string cmdText = "SELECT ThumbNailPhoto FROM Production.[ProductPhoto] WHERE ProductPhotoID=@PhotoID";
// Get an array of bytes from the BLOB field
byte[] img = null;
SqlConnection conn = new SqlConnection(connString);
using (conn)
{
SqlCommand cmd = new SqlCommand(cmdText, conn);
cmd.Parameters.AddWithValue("@PhotoID", id);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
reader.Read();
img = (byte[])reader[0];
conn.Close();
}
// Prepare the response for the browser
if (img != null)
{
context.Response.ContentType = "image/jpeg";
context.Response.BinaryWrite(img);
}
}
public bool IsReusable {
get {
return false;
}
}
}
This HTTP handler is very much like the one in the previous sample, except the ADO.NET related components work. Here we specify the ContentType property of HttpResponse as "image/jpeg" and then use the BinaryWrite() method to write the image data to the output stream.
Please note, for integrity, I've also provided the more generic way to write the HTTP handler. Below I've listed several points to notice:
1) Add a new project at the web site named DatabaseHTTPHandler, and in the default file Class1.cs write the above HTTP handler (you will need to add related references to the required system assemblies).
2) Build the DatabaseHTTPHandler project, and you will get an assembly named DatabaseHTTPHandler.dll.
3) Add the reference to the DatabaseHTTPHandler.dll assembly to the above web site project AspnetGdiplus.
4) Register the related information in the web.config file, as follows:
<httpHandlers>
......
<add verb="*" path="ImageHandler.axd" type="DatabaseHTTPHandler.ImageHandler, DatabaseHTTPHandler" validate="false"/>
</httpHandlers>
5) Use the custom HTTP handler, as shown in the above-mentioned Button1_Click function (the commented line).
For all the details, please see the attached source code with this article.
For now, we've only tackled half of the problem-accessing image data in database. The other half we've not looked at so far is how to store image data in a database. In fact, I have already given the answer for this half in my article (one of a long series) ' Back-end Management Tasks for an ASP.NET AJAX Server-Centric Based Online Shopping Website '.
Now that you know the key for the second half, let's go on with the story-dynamically generating images using GDI+ and more.
Author's Note: Whether to persist image data in databases depends on many concrete conditions, such as the size of a single image file, the number of image files, the kind of database, the memory volume of the backend, and whether to leverage the ASP.NET buffering mechanism. In practical scenarios, sometimes you can store image files under some sub folders in the website. Sometimes if the sizes and number of image files meet specified conditions, you can also take into account the buffering technique. In Dino Esposito's opinion, if you frequently edit the images, you'd better persist the image files in an independent file form. If the image files are huge (tens or hundreds of mega-bytes) you are also advised to store them in the file system form, while if the images are mainly read-only and static as well as small (less than thousands of bytes), the database solution will be your best choice.
-DOWNLOAD SOURCE PART 1-
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |