Loading Images Asynchronously Inside an ASP.NET GridView

Posted by: Suprotim Agarwal , on 8/26/2008, in Category ASP.NET
Views: 157251
Abstract: Retrieving and displaying images in a GridView is a time consuming task. If done synchronously, this task can at times test the user’s patience. One way to provide a good user experience is to load the images asynchronously. So when the GridView loads, we initially display a default image for the user to view, while the actual images are being loaded from the database. In this article, we will see how to do so.
Loading Images Asynchronously Inside an ASP.NET GridView
 
Retrieving and displaying images in a GridView is a time consuming task. If done synchronously, this task can at times test the user’s patience. One way to provide a good user experience is to load the images asynchronously. So when the GridView loads, we initially display a default image for the user to view. We then retrieve the actual images asynchronously from the database. In this article, we will see how to do so.
For readability purpose, I have not covered any validations in the sample. The article focuses on how to read images asynchronously from the database and display it in the GridView control. I assume you have some knowledge of creating ASP.NET 3.5 websites. We will be using Visual Studio 2008 for this article.
I am using a sample database that has been pre-populated with some data. You can replace this sample to target your own database and table. The definition of my table is as follows:
CREATE DATABASE [PictureAlbum]
GO
USE [PictureAlbum]
GO
CREATE TABLE Album
(
pic_id int IDENTITY NOT NULL,
picture_tag varchar(50),
pic image
)
Step 1: Create an ASP.NET website. Drag and drop a ‘SqlDataSource’ Control to the page and use the wizard to connect to the ‘PictureAlbum’ database. Select the pic_id, picture_tag columns from the Album table. The wizard will also prompt you to save the connection string in the web.config file. Choose to do so. The design code will look similar to the following:
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
    ConnectionString="<%$ ConnectionStrings:PictureAlbumConnectionString %>"
    SelectCommand="SELECT [pic_id], [picture_tag] FROM [Album]">
</asp:SqlDataSource>
An entry will be added to the web.config file as shown below:
      <connectionStrings>
            <add name="PictureAlbumConnectionString" connectionString="Data Source=.;Initial Catalog=PictureAlbum;Integrated Security=True" providerName="System.Data.SqlClient"/>
      </connectionStrings>
Step 2: Now add a GridView control to the page. Set its ‘AutoGenerateColumns’ property to false. Using the smart tag, select the DataSource to be ‘SqlDataSource1’ in the GridView tasks panel. Using the same panel, click on the Enable Paging checkbox. The source will look similar to the following.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataSourceID="SqlDataSource1" AllowPaging="True">
    <Columns>
        <asp:BoundField DataField="pic_id" HeaderText="Picture ID" InsertVisible="False"
            ReadOnly="True" SortExpression="pic_id" />
        <asp:BoundField DataField="picture_tag" HeaderText="Tags"
            SortExpression="picture_tag" />
    </Columns>
</asp:GridView>
 
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
    ConnectionString="<%$ ConnectionStrings:PictureAlbumConnectionString %>"
    SelectCommand="SELECT [pic_id], [picture_tag] FROM [Album]">
</asp:SqlDataSource>
Step 3: We will now add an <ItemTemplate> to the GridView to display the images. When the GridView is displayed to the user, we will be showing a default image (using the ‘src’ attribute of the image) which will be quickly downloaded and displayed to the user. Then using the onLoad() event of the image, we will retrieve the actual image from the database. The onLoad() will point to a javascript function which will give a call to an ‘image handler’ to retrieve the image from the database. It is this javascript function called ‘RetrieveImage()’ which does the part of performing the operation asynchronously. The <ItemTemplate> code will look similar to the following:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataSourceID="SqlDataSource1" AllowPaging="True">
    <Columns>
        <asp:BoundField DataField="pic_id" HeaderText="pic_id" InsertVisible="False"
            ReadOnly="True" SortExpression="pic_id" />
        <asp:BoundField DataField="picture_tag" HeaderText="picture_tag"
            SortExpression="picture_tag" />
            <asp:TemplateField>
                <HeaderTemplate>Picture</HeaderTemplate>
                <ItemTemplate>
                    <img border="1" src="images/cursor.jpg" onerror="this.src='images/error.jpg'" onload="RetrievePicture(this,'<%# Eval("pic_id")%>');"/>
                </ItemTemplate>
            </asp:TemplateField>
    </Columns>
</asp:GridView>
The javascript function declared in the <head> will be as follows:
<head runat="server">
    <title>Asynchronous Image</title>
    <script type="text/javascript" language="javascript">
        function RetrievePicture(imgCtrl, picid)
        {  
            imgCtrl.onload = null;
            imgCtrl.src = 'ShowImage.ashx?id=' + picid;
        }
    </script>
</head>
This function accepts a reference to the image control and the picture id, that is passed using the ‘Eval(“pic_id”)’ expression. The javascript function then gives a call to an image handler covered in the next step. The function passes the picture id to the handler and receives the image associated with the handler, which it binds to the image using 'imgCtrl.src'.
Step 4: In order to display the image on the page, we will create an Http handler. To do so, right click project > Add New Item > Generic Handler > ShowImage.ashx. Add the code shown below to the handler.
C#
<%@ WebHandler Language="C#" Class="ShowImage" %>
 
using System;
using System.Configuration;
using System.Web;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Drawing.Imaging;
using System.ComponentModel;
 
public class ShowImage : IHttpHandler
{
    long seq = 0;
    byte[] empPic = null;
 
    public void ProcessRequest(HttpContext context)
    {
        Int32 picid;
        if (context.Request.QueryString["id"] != null)
            picid = Convert.ToInt32(context.Request.QueryString["id"]);
        else
            throw new ArgumentException("No parameter specified");
 
        // Convert Byte[] to Bitmap
        Bitmap newBmp = ConvertToBitmap(ShowAlbumImage(picid));
        if (newBmp != null)
        {
            newBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
            newBmp.Dispose();
        }
 
    }
 
    // Convert byte array to Bitmap (byte[] to Bitmap)
    protected Bitmap ConvertToBitmap(byte[] bmp)
    {
        if (bmp != null)
        {
            TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap));
            Bitmap b = (Bitmap)tc.ConvertFrom(bmp);
            return b;
        }
        return null;
    }
 
    public byte[] ShowAlbumImage(int picid)
    {
        string conn = ConfigurationManager.ConnectionStrings["PictureAlbumConnectionString"].ConnectionString;
        SqlConnection connection = new SqlConnection(conn);
        string sql = "SELECT pic FROM Album WHERE Pic_ID = @ID";
        SqlCommand cmd = new SqlCommand(sql, connection);
        cmd.CommandType = CommandType.Text;
        cmd.Parameters.AddWithValue("@ID", picid);
        try
        {
            connection.Open();
            SqlDataReader dr = cmd.ExecuteReader();
            if (dr.Read())
            {
                seq = dr.GetBytes(0, 0, null, 0, int.MaxValue) - 1;
                empPic = new byte[seq + 1];
                dr.GetBytes(0, 0, empPic, 0, Convert.ToInt32(seq));
                connection.Close();
            }
 
            return empPic;
        }
 
        catch
        {
            return null;
        }
        finally
        {
            connection.Close();
        }
    }
 
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
 
 
}
 
 
VB.NET
<%@ WebHandler Language="vb" Class="ShowImage" %>
 
Imports System
Imports System.Configuration
Imports System.Web
Imports System.IO
Imports System.Data
Imports System.Data.SqlClient
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.ComponentModel
 
Public Class ShowImage
      Implements IHttpHandler
      Private seq As Long = 0
      Private empPic() As Byte = Nothing
 
      Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
            Dim picid As Int32
            If context.Request.QueryString("id") IsNot Nothing Then
                  picid = Convert.ToInt32(context.Request.QueryString("id"))
            Else
                  Throw New ArgumentException("No parameter specified")
            End If
 
            ' Convert Byte[] to Bitmap
            Dim newBmp As Bitmap = ConvertToBitmap(ShowAlbumImage(picid))
            If newBmp IsNot Nothing Then
                  newBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg)
                  newBmp.Dispose()
            End If
 
      End Sub
 
      ' Convert byte array to Bitmap (byte[] to Bitmap)
      Protected Function ConvertToBitmap(ByVal bmp() As Byte) As Bitmap
            If bmp IsNot Nothing Then
                  Dim tc As TypeConverter = TypeDescriptor.GetConverter(GetType(Bitmap))
                  Dim b As Bitmap = CType(tc.ConvertFrom(bmp), Bitmap)
                  Return b
            End If
            Return Nothing
      End Function
 
      Public Function ShowAlbumImage(ByVal picid As Integer) As Byte()
            Dim conn As String = ConfigurationManager.ConnectionStrings("PictureAlbumConnectionString").ConnectionString
            Dim connection As New SqlConnection(conn)
            Dim sql As String = "SELECT pic FROM Album WHERE Pic_ID = @ID"
            Dim cmd As New SqlCommand(sql, connection)
            cmd.CommandType = CommandType.Text
            cmd.Parameters.AddWithValue("@ID", picid)
            Try
                  connection.Open()
                  Dim dr As SqlDataReader = cmd.ExecuteReader()
                  If dr.Read() Then
                        seq = dr.GetBytes(0, 0, Nothing, 0, Integer.MaxValue) - 1
                        empPic = New Byte(seq){}
                        dr.GetBytes(0, 0, empPic, 0, Convert.ToInt32(seq))
                        connection.Close()
                  End If
 
                  Return empPic
 
            Catch
                  Return Nothing
            Finally
                  connection.Close()
            End Try
      End Function
 
      Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
            Get
                  Return False
            End Get
      End Property
 
 
End Class
 
The steps for retrieving the image from the database, using the handler are as follows:
1.    The ID is passed to the handler via query string. We use the Request.QueryString[“id”] to retrieve the PictureID(pic_id) from the handler url. The ID is then passed to the ‘ShowAlbumImage()’ method where the image is fetched from the database using SqlDataReader and returned in a byte[] object.
2.    We pass this byte[] to the ConvertToBitmap() function where we use the TypeConverter class to convert a byte array to bitmap.
3.    The last step is to save the image to the page's output stream and indicate the image format as shown here newBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg)
That’s it. Run the application. When the application loads initially, it displays a default image as shown below. Please use a nice 'progress bar like' logo in your application and apologies for this roughed up image shown below. 
Default Image
The actual images are then loaded one by one from the database using the image handler as shown below:
 Actual Image
Using the technique discussed in this article, you can use a little bit of javascript in your asp.net page to retrieve the image asynchronously from the database. Not only does it provide a good user experience, but it also enables you to have control over the images being retrieved. The source code of this article in C# and VB.NET can be downloaded from here. I hope this article was useful and I thank you for viewing it.

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of DotNetCurry, DNC Magazine for Developers, SQLServerCurry and DevCurry. He has also authored a couple of books 51 Recipes using jQuery with ASP.NET Controls and The Absolutely Awesome jQuery CookBook.

Suprotim has received the prestigious Microsoft MVP award for Sixteen consecutive years. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.

Get in touch with him on Twitter @suprotimagarwal or at LinkedIn



Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by packiaraj on Wednesday, August 27, 2008 8:22 AM
your coding really superb...
Comment posted by Scott on Wednesday, August 27, 2008 12:12 PM
Should'nt we use BeginExecuteReader() and EndExecuteReader() in ADO.Net 2.0 to read image asynchronously from database?
Comment posted by Tim on Thursday, August 28, 2008 1:44 AM
I guess, to read something asynchronously from DB we shld use BeginExecuteReader() and EndExecuteReader() in ADO.Net 2.0. I guess the title "Loading Images Asynchronously..." is misleading here..
Comment posted by Suprotim Agarwal on Thursday, August 28, 2008 2:57 AM
Scott, Tim: Thanks for your comments. The context of the article is to show how 'javascript' can be used in asp.net to perform time consuming tasks. There are multiple ways of handling images in the gridview, one of the ways like you described or may be another, by using image caching to reduce the load.

Also, since the article focuses on loading images asyc, the technique described here can be used to load images from an external source too, not necessarily from the db itself. A small change in the ShowAlbumImage method could do that!!
Comment posted by john on Friday, August 29, 2008 7:52 AM
Works great but for the really troublesome error message which popus up for each image. "Stack overflow at line 0".

I have copied your example and did nothing but change database details.

Why is this happening?...how can i resolve it?
I have been struggling with this for 2 days now.

thanks!
Comment posted by Suprotim Agarwal on Friday, August 29, 2008 11:41 AM
John: Did you try downloading the source code of this article and try it out
Comment posted by Thargol on Saturday, August 30, 2008 12:59 PM
What about the "lowsrc" attribute on images? This is meant a solution for the problem mentioned...
Comment posted by Dimitris on Monday, September 1, 2008 11:43 AM
I get onerror is not a valid attribute for element "img".
How can I set an image in case of an error
Comment posted by Suprotim Agarwal on Monday, September 1, 2008 9:36 PM
Dimitris: How are you specifying the onerror attr. It should be like this:

<img border="1" src="images/cursor.jpg" onerror="this.src=images/error.jpg" onload="RetrievePicture(this,'<%# Eval("pic_id")%>');"/>
Comment posted by balakrishnay on Tuesday, September 2, 2008 12:46 PM
I am well satisfied in this site, mainly code vary clear and understanding this eample
Comment posted by Morteza on Tuesday, September 16, 2008 3:48 AM
Hi Suprotim Agarwal, thanks for good article
but source code has a problem. in javascript function you used:
"imgCtrl.onLoad = null"
but onload is Case Sensitive in javascript and you should use:
"imgCtrl.onload = null"
Comment posted by Morteza on Tuesday, September 16, 2008 3:54 AM
And another solution,
after you retrieve image from database as Stream, you may use this trick instead of reading bytes from stream and writing in Loop.

Stream strm = ShowAlbumImage(picid);
Bitmap bmp = new Bitmap(strm);
bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
Comment posted by Suprotim Agarwal on Tuesday, September 16, 2008 9:17 AM
Morteza, thanks for your comments. I have used onload. Which code are you referring to?

<img border="1" src="images/cursor.jpg" onerror="this.src=images/error.jpg" onload="RetrievePicture(this,'<%# Eval("pic_id")%>');"/>

Comment posted by Morteza on Saturday, September 20, 2008 6:19 AM
As i mentioned, in javascript function in csharp version code you use:

function RetrievePicture(imgCtrl, picid)
        {
            imgCtrl.onLoad = null;
            imgCtrl.src = 'ShowImage.ashx?id=' + picid;
        }

As you see,"onLoad" has UpperCase "L" and it should be "onload"
Comment posted by Suprotim Agarwal on Sunday, September 21, 2008 3:58 AM
Morteza: It seems I missed out adding that line in this article, whereas I kept in on the code attached with this article.

The javascript function on the page looks like this:

    <script type="text/javascript" language="javascript">
        function RetrievePicture(imgCtrl, picid)
        {
            imgCtrl.src = 'ShowImage.ashx?id=' + picid;
        }
    </script>

I missed out on the onload (strange dunno why I did that!!)

Anyways, thanks for letting me know.
Comment posted by Sean on Saturday, October 4, 2008 2:22 PM
Hi,
On Building my website when using this code displays and error. stating server tag not well formed. What can I do to solve the error.
<img border="1" src="images/cursor.jpg" onerror="this.src=images/error.jpg" onload="RetrievePicture(this,'<%# Eval("pic_id")%>');"/>
Comment posted by Kim Andersen on Sunday, November 23, 2008 3:08 AM
I wouldn't recommend this approach. The problem is that a trip to the database is made each time an image is loaded async. So if you have a grid of 20 rows, 21 trips to the database is made, which is very bad for performance. You might not "feel" the performance hit when viewing this grid/page. But other pages will be slower because the web server is relatively busy doing the database work.
Comment posted by Voytek on Sunday, November 23, 2008 10:00 AM
It seems to be the perfect receipt for performance killer. First store images in the database and next use cursor approach to retrieve the data.
Of course one can argue that for security reasons images have to be stored in DB. In such cases other solutions like small thumbnails and paging are better approach.
Putting all this criticism aside, the concept of populating the grid with generic images and bringing the final ones later is really interesting.  
Comment posted by Thanigainathan S on Sunday, November 23, 2008 11:17 AM
Hi,

This article is really superb. But instead of using a handler you can use page methods or ICallbackeventhandler to call a server method asynchronously. They are more efficient than this.

Thanks ,
Thani
Comment posted by Peter on Sunday, November 23, 2008 4:17 PM
Can browsers still cache the images?
Comment posted by James on Sunday, November 23, 2008 8:58 PM
I don't understand whats the intention of publishing this type of article on www.asp.net site. If you search internet you would find hundres of this type of similar articles. Also I could't see any asynchronous action in the code although it uses javascript to retrieve image.

We should expect much better quality article in such an important web site www.asp.net.
Comment posted by Suprotim Agarwal on Sunday, November 23, 2008 10:12 PM
Thanks everyone for their very valuable comments. Most of them are valid in their own context. One of the users had asked me how to populate the Grid with images stored in a db by first displaying a default image and then loading up the actual images, and this had to be done using javascript and an image handler(since she later wanted to add a copyright notice to the image). I had suggested her the method shown in this article.

However suggestions to make the call async are well taken and accepted. Thanks. Keep the comments coming!
Comment posted by Haresh Chaudhari on Monday, November 24, 2008 12:39 AM
First of all i want to say Thanks to Suprotim Agarwal for this article. This article really helpful for me, when i came to this Loading Images Asynchronously Inside GridView, i tried to search on Asp.Net site and i found this one helpful for me.
Thank you once again for this article.
Comment posted by وستا on Monday, November 24, 2008 2:13 AM
i changed your code and modified it for loading images from files to use for large images and used filestream to read and write images to buffer but my page will remain getting data.what is the problem.i didn't test your sample code,has it any similar problem or not?
Comment posted by phenix on Monday, November 24, 2008 3:19 AM
I agree with Kim Andersen,there are too many times trip DB.
Comment posted by CyberLib on Monday, November 24, 2008 3:42 AM
i used this source for png picture files and it caused the GDI+ error!
Comment posted by Gunteman on Monday, November 24, 2008 2:50 PM
Yes, there are quite a few roundtrips to the, but this is still a very valid approach.
Comment posted by EvanLarsen on Tuesday, November 25, 2008 10:37 AM
Yes there are a lot of round trips BUT that can easily be solved.  The point of this guys article is to show how to load a default "loading" image and then after the content has been shown to the user, asynchronously load in the other images.
To save round trips all you have to do is query the DB once for all the images on the page, store it in a session variable and then access that, session variable, to refer to the image names.
Comment posted by Ryan Davis on Tuesday, November 25, 2008 12:39 PM
remember to employ the C# "using" statement when dealing with unmanaged resources like db connections, see http://msdn.microsoft.com/en-us/library/yh598w02(VS.80).aspx and http://davidhayden.com/blog/dave/archive/2005/01/13/773.aspx for more information.
Comment posted by Suprotim Agarwal on Wednesday, November 26, 2008 12:23 PM
Cyberlib: What's the contentType set to?

Gunteman, Evan: Thanks for understanding the context of this article!

Ryan: Yes the 'using' block is very handy and important. Anyways I have used the finally and called the Close() in it. Anyways as you mentioned, the 'using' block is much easier to use without the hassles of the finally block.

@All: Thanks for all your comments!!
Comment posted by Mujib on Wednesday, November 26, 2008 11:37 PM
What is this?

Stack overflow at line : 0
Comment posted by max on Thursday, November 27, 2008 5:39 AM
in ie7 popups: "Stack overflow at line 0".
good in firefox, dows not show image in google chrome
Comment posted by Suprotim Agarwal on Thursday, November 27, 2008 9:55 PM
Mujib, Max: Did you download the source code and test it out? Can you send me a link to the screenshot using the Contacts page. THanks.
Comment posted by krishhhh on Friday, December 5, 2008 6:39 PM
Can we put an image button instead of image, coz I want to have a bigger image when we click on the image???
Comment posted by Dilli.Babu on Tuesday, December 9, 2008 8:52 AM
Really cool solution, help a lot in real time scenerio
Comment posted by Rick on Tuesday, December 16, 2008 11:26 PM
I downloaded the source and I get stack over flow at line 0 in an aleart pop uu and I have to click Ok For every picture
Comment posted by Rick on Tuesday, December 16, 2008 11:41 PM
I"m a self taught novice/begginer I'm working on a asp.net 3.5 site with membership I want to display a picture From a table that has a GUID primary key, varbinary(max)data type  and a foreign key to userId also a Guid there's got to be an easier why to display pictures from a data base can any on point me to source or tutorial with tweekable code that I can make work on my project. They should have a control you can drag in to a gridview point it to a database table/column set the width and hieght and go on  
Comment posted by Rick on Wednesday, December 17, 2008 1:27 AM
I got rid of the stack overflow at line 0 aleart by changing onLoad to onload some Imaging sizing coade for this Handler would be nice
Comment posted by rick on Friday, December 19, 2008 6:29 PM
can any one tell me how I could modify this so its not loading
Asynchronously so we can set trace to true and see how much faster the same coade is
Comment posted by Dusty on Monday, December 22, 2008 9:13 AM
here is another good example: http://laymensterm.blogspot.com/2008/12/simple-aspnet-vbnet-database-connection.html
Comment posted by gf on Tuesday, January 13, 2009 11:10 AM
First of all I want to say Thanks to Suprotim's article. It is really helpful for me.
I just wondaring if any body solved the "stack overflow at line 0" issue?
Comment posted by gf on Tuesday, January 13, 2009 12:00 PM
First of all I want to say Thanks to Suprotim's article. It is really helpful for me.
I just wondaring if any body solved the "stack overflow at line 0" issue?
Comment posted by gf on Tuesday, January 13, 2009 12:55 PM
First of all I want to say Thanks to Suprotim's article. It is really helpful for me.
I just wondaring if any body solved the "stack overflow at line 0" issue?
Comment posted by Robert on Sunday, January 18, 2009 1:01 PM
It looks like great code, but it doesnot work at my place. I copied everything to my computer, changed the database to my database and the result is the famous red cross: no image. Furthermore I have the same problem as Dimitris: onerror doesnot work either. In short: what can be the problem? I use the VB-variant.
Comment posted by Robert on Monday, January 19, 2009 3:10 PM
I hope that my message is read, because it really looks like great code and thus it would be a pity I cannot use it. To give an idea from my end-result serves the following code from my default.aspx:

<%@ Page Language="VB" AutoEventWireup="false"
CodeFile="Default.aspx.vb" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Asynchronous Image</title>
    <script type="text/javascript" language="javascript">
        function RetrievePicture(imgCtrl, picid)
        {
            imgCtrl.onload = null;
            imgCtrl.src = 'ShowImage.ashx?id=' + picid;
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>    
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataSourceID="SqlDataSource1" AllowPaging="True">
    <Columns>
        <asp:BoundField DataField="pic_id" HeaderText="pic_id" InsertVisible="False"
            ReadOnly="True" SortExpression="pic_id" />
            <asp:TemplateField>
                <HeaderTemplate>Picture</HeaderTemplate>
                <ItemTemplate>
                    <img alt="pic" src="images/cursor.jpg" onload="RetrievePicture(this,'<%# Eval("pic_id")%>');"/>
                </ItemTemplate>
            </asp:TemplateField>
    </Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
    ConnectionString="<%$ ConnectionStrings:WielerDatabaseSQLConnectionString %>"
    SelectCommand="SELECT [pic_id] FROM [vwGirokaartDropDown]">
</asp:SqlDataSource>
    
    </div>
    </form>
</body>
</html>

I hope that this will help to find an answer. Thanks in advance.
Comment posted by Suprotim Agarwal on Thursday, January 22, 2009 11:59 AM
Robert: Thanks for your patience. I know it's been quiet a while since you posted your question. Kindly wait for a couple of hours more and I will post the solution once I get to my machine..I am travelling currently.

Meanwhile, did you check out the C# code, just to make sure it runs at your end?

Thanks
Comment posted by Robert on Friday, January 23, 2009 3:20 AM
Hello Suprotim,
Yes, I checked the C#-code and it runs at my end.
I patiently wait for your answer, so don't hurry.
Robert.
Comment posted by Suprotim Agarwal on Monday, January 26, 2009 4:51 AM
Robert: Thanks for your patience. I have made some changes and re-uploaded the samples. Please check the code and let me know if you face any more issues.

Thanks everyone else for their comments!
Comment posted by Robert on Tuesday, January 27, 2009 4:39 PM
Hello Suprotim: thanks voor your reaction and changes in code. The bad news is that it won''t work at my side (we talk about the VB-option). I get the following errors (the second and third are in the handler, the first is not relevant I think):

Error   1   Een sectie die is geregistreerd als allowDefinition='MachineToApplication' mag niet worden gebruikt buiten het toepassingsbereik. Deze fout kan worden veroorzaakt doordat een virtuele map niet is geconfigureerd als toepassing in IIS.   C:\Users\Robert\Documents\Visual Studio 2008\WebSites\DotNetCurry\AsyncImagesGridView\web.config   48   
Error   2   Value of type 'System.IO.Stream' cannot be converted to '1-dimensional array of Byte'.   C:\Users\Robert\Documents\Visual Studio 2008\WebSites\DotNetCurry\AsyncImagesGridViewVB\ShowImage.ashx   29   48   C:\...\DotNetCurryError   3   Value of type '1-dimensional array of Byte' cannot be converted to 'System.IO.Stream'.   C:\Users\Robert\Documents\Visual Studio 2008\WebSites\DotNetCurry\AsyncImagesGridViewVB\ShowImage.ashx   66   20   C:\...\DotNetCurry
It is the same mistake round empPic. Your code is to complicated for me to find the error myself, sorry. I hope you can help me out with this problem. Thanks a lot in advance, Robert.

(PS Something went wrong in sending, so it is possible you get the message twice)
Comment posted by Angel Escamilla on Thursday, February 26, 2009 4:55 AM
Wonderful example, just what I was looking for... I downloaded the files and modified them to connect to mySQL instead of MS-SQL. Works like a charm!
Comment posted by Suprotim Agarwal on Thursday, February 26, 2009 6:38 AM
Angel: Thanks. Glad you liked it!
Comment posted by Dan on Friday, March 13, 2009 8:53 PM
Hello gentlemen,

I got a "stack overflow at line : 0" when I'm trying to adapt the code in my application and don't find why...

Any idea?
Comment posted by Stephen on Friday, March 13, 2009 11:23 PM
Good finally something about loading images from a database... was hard to find.

Thanks Suprotim Agarwal for this.

Seems to work except I have the same problem than Max, gf, Mujib and Dan with the "stack overflow at line : 0" and there is no real answer in the comments about it.

Maybe you can help?!?
Comment posted by Suprotim Agarwal on Sunday, March 15, 2009 1:59 AM
Stephen: I did change code to fix it a few weeks ago. Have you downloaded the code(both C# and VB.NET) and tried it again?
Comment posted by Robert on Tuesday, March 17, 2009 3:18 AM
Dear Suprotim,
Is there any solution for my problem of jan 27th? Or is your advise running out of options - what I would understand. I hope to hear from you, Robert
Comment posted by Suprotim Agarwal on Tuesday, March 17, 2009 5:27 AM
Robert: Your comment surprises me! I had changed the code and uploaded the new one after receiving your comment to fix the error. I have now also added the database to be sure that we are checking against the same code base and that the code works in both C# and VB.NET. Please download the code again, and take a look at the ReadMe.txt. Free feel to post additional comments.
Comment posted by Stephen on Tuesday, March 17, 2009 9:57 PM
With your code it is working fine but with mine I get a stack overflow at line:0

I did just adapt your code for my code and I always get this error message.

Question: do your code stock in the buffer all the images from the database or only the one asked in the querystring?

I'm getting mad with this would be nice if you can help, Stephen
Comment posted by Suprotim Agarwal on Wednesday, March 18, 2009 6:56 AM
Stephen: It looks like the onError() is setting the image to a default path. Try removing the onError() from the img and run the code. Also specify a size to the image.
Comment posted by rasoulghaffari on Wednesday, March 18, 2009 11:30 AM
Very beautiful descriptionDescription And Sample thank you very much
Comment posted by Robert on Friday, March 20, 2009 9:20 AM
Suprotim, thanks for your reaction. I am sorry to say this, but the error remains.
When you look into the code the system says on ConvertToBitmap (ShowAlbumImage(picid)) the following error Value of type 'System.IO.Stream' cannot be converted to '1-dimensional array of Byte'. Further on at Return empPic it says Value of type '1-dimensional array of Byte' cannot be converted to 'System.IO.Stream'. The first one produces the error, the second one follows the first.
For clarity: I used your new code. Something goes wrong i  the array-thing. Perhaps you want to give it one more try?
Thanks, Robert.
Comment posted by Adnan Sohail on Friday, March 27, 2009 4:14 PM
Code runs fine .. but i get overflow exception. I put an alert in the javascript that retrieves image and that alert was firing like crazy. I believe that is the reason for overflow exception.

Has anyone been able to fix it?
Comment posted by Suprotim Agarwal on Saturday, March 28, 2009 2:57 PM
Robert, Adnan: Let me try it with a different set of images and check if I can reproduce the error over here. Thanks all for your patience!
Comment posted by malik abid on Saturday, April 18, 2009 7:37 AM
the code is superb but there is some problem
i m working on an asp.net 2.0 site
i used gridview and ur coding to display images stored in database
it worked fine except one thing...
the code does not stop when the page is run
images are displayed but the code still keeps running showing([n] items remaining)..
please help me out to debug this code..
one more thing..
i m using master page so there is no head section for the script so i m using the script tag inside the
contentplaceholder...


plz help
Comment posted by malika abid on Monday, April 20, 2009 2:49 AM
hi friends! i found the sol to my problem...

just a little modification at step 3...

<asp:TemplateField>
                <HeaderTemplate>Picture</HeaderTemplate>
                <ItemTemplate>
                  <img alt="category image" src="ShowImage.ashx?id=<%# Eval("CategoryID")%>"height="100" width="100" />
                </ItemTemplate>
                <EditItemTemplate>
                    <asp:FileUpload ID="FileUpload1" runat="server" />
                </EditItemTemplate>
            </asp:TemplateField>

hope it will work as it workd for me..
thank u..
Comment posted by Suprotim Agarwal on Tuesday, April 21, 2009 8:58 AM
Malika: Thanks for the tip. I am sure people will find it useful. I had mentioned a tip to add size to the image in my reply earlier to Stephen. However if specifying the src as the url directly helps instead of calling the RetrievePicture, please use so.
Comment posted by Girish Sharma on Saturday, June 27, 2009 1:39 AM
I have following requirement:
Table Name:StudentData
Name,RollNumber,ImagePath

Using VS 2005
I have a web page in which i have placed crystal report viewer control and created a crystereport.  Now i wish to show the image on the web page as per image path of the table.

How do i achieve this.
Please guide me.
Thank you.
Girish Sharma
Comment posted by Suprotim Agarwal on Thursday, July 2, 2009 2:21 AM
Girish: Your question is out of scope for this article as I do not cover Crystalreports. You can try the forums at http://forums.asp.net and post your question there.
Comment posted by K S on Tuesday, July 14, 2009 7:22 PM
For those of you having trouble with 'Stack overflow at line 0', make sure you have following code:

    <script type="text/javascript" language="ecmascript">
        function GetPicture(imgCtrl, picId) {
            imgCtrl.onload = null;
            imgCtrl.src = 'ShowImage.ashx?id=' + picId;
        }
    </script>

The article does not have the line imgCtrl.onload = null;
Comment posted by Sobin on Friday, January 1, 2010 3:26 AM
Hi Sir,
I have one doubt.If my gridview page size is larger (eg ;50),then won't the http handler open and close database connection that much times? Is this feasible? Any other alternative available for the same case?Please clarify my doubt..
Regards
Comment posted by Suprotim Agarwal on Tuesday, January 5, 2010 3:58 AM
Sobin: Yes that's right and it will open the connection those many times. Alternatively, you can read images from the disk as shown here http://msdn.microsoft.com/en-us/library/aa479350.aspx
Comment posted by Ben Yu on Sunday, February 7, 2010 10:24 PM
Hi,

I want to popup an enlarged image when you click on one of the images on the grid. but the 'img' object does not have a onclick event. How do you accomplish this?
Comment posted by Suprotim Agarwal on Monday, February 8, 2010 5:11 AM
Ben: Just search out for 'Image Popup with jQuery' in your search engine and you will get plenty of examples. You might also want to look at jQuery UI Dialog plugins like the ThickBox  http://jquery.com/demo/thickbox/
Comment posted by Shiva on Wednesday, March 17, 2010 11:40 PM
Hi Suprotim Agarwal,
First of all thank you so much for the code. I have an issue while running your code and i believe it must be from my side as your code seem to be fine based on peoples comments. This is the issue, for some reason i can't display my images. it just display the cursor.jpg

Attached is my code and hoping for a solution. thanks in advance


Regards

<head runat="server">
  <title>Asynchronous Image</title>
    <script type="text/javascript" language="javascript">
        function RetrievePicture(imgCtrl, picid)
        {
            imgCtrl.onload = null;
            imgCtrl.src = 'ShowImage.ashx?id=' + picid;
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        <asp:SqlDataSource ID="SqlDataSource1" runat="server"
            ConnectionString="<%$ ConnectionStrings:NrityamDB %>"
            
            SelectCommand="SELECT [img_pk], [img_name],[img_data], [img_contenttype] FROM [image]">
        </asp:SqlDataSource>
    
    </div>
    <asp:GridView ID="GridView1" runat="server" AllowPaging="True"
        AutoGenerateColumns="False" DataKeyNames="img_pk" DataSourceID="SqlDataSource1">
        <Columns>
            <asp:BoundField DataField="img_pk" HeaderText="img_pk" InsertVisible="False"
                ReadOnly="True" SortExpression="img_pk"/>
            <asp:BoundField DataField="img_name" HeaderText="img_name"
                SortExpression="img_name" />
                        
                </asp:ImageField>
            <asp:BoundField DataField="img_contenttype" HeaderText="img_contenttype"
                SortExpression="img_contenttype" />
                <asp:TemplateField>
                <HeaderTemplate>Picture</HeaderTemplate>
                <ItemTemplate>
                  
                    <img alt="img_data" src="ShowImage.ashx?id=<%# Eval("img_pk")%>"height="100" width="100" />

                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>
    </form>
</body>
</html>
Comment posted by wooer on Friday, June 11, 2010 8:52 AM
I also had the stack overflow error. And after implementing several solutions given here "K S"' solution solved my problem. Thanks "K S". Just add imgCtrl.onload = null; statement.

Thanks or great article but if there would be some validations especially on images it would be more complete.
Comment posted by frank on Wednesday, June 23, 2010 9:20 PM
Stack overflow solution:
Do not miss this javascript line: imgCtrl.onload = null;
Hope this can help.
Comment posted by Bayo on Friday, August 27, 2010 9:39 AM
when I insert picture through using VB code, I do have double entry of record. But with C# it is only single entry.
Please, how can I solve this problem.
Comment posted by Gaurav Yadav on Friday, January 6, 2012 2:49 AM
Hi,

I was reading your article and I would like to appreciate you for making it very simple and understandable. This article gives me a basic idea of Dynamically loading image in Image control in ASP.NET and it helped me a lot. I had found another nice post over the internet which also have a wonderful explanation on Dynamically loading image in Image control in ASP.NET, for more details of that post you may visit this url...
http://www.mindstick.com/Articles/c98d98d1-3186-4cac-9069-304b08a269d3/?Dynamically%20loading%20image%20in%20Image%20control%20in%20ASP.NET

Thank you very much for your precious post.
Comment posted by vihar on Monday, March 5, 2012 12:07 AM
I get onerror is not a valid attribute for element "img".
How can I set an image in case of an error

and i am writing like this but i m getting error
<img border="1" src="images/cursor.jpg" onerror="this.src=images/error.jpg" onload="RetrievePicture(this,'<%# Eval("pic_id")%>');"/>

can any one help me to findout the error
Comment posted by Viral Prajapati on Saturday, May 26, 2012 12:36 AM
i want to display image directly through database from varbinary(max) datatype in gridview through "sqldatasource" control.i can implement it through http handler.but i also want to give facility to gridview to "insert and update image through fileupload contol" in varbinary(max) datatype only through "sqldatasource" control.pls help me sir.