I am storing images in SQL Server 2000 database (BLOB type). There is a web page in my ASP.NET application which need to show a lot images to the end user and i want to handle browser's requests for images through a IHttpAsyncHandler. I found a similer post on codeproject "Asynchronous HTTP Handler for Asynchronous BLOB DataReader." But for some reasons, page get freeze upon completion of "BeginProcessRequest" method and "EndProcessRequest" method never get call. Can anyone look at this post and let me know whats wrong in that post? OR what i need to do to complete this task (BLOB Reading via IHttpAsyncHandler)?
The source code in this post is as under,
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
try
{
// image to retrieve
// this needs to change if setup a different path schema in the httpHandles web.config
string imgId = context.Request.Url.Segments[context.Request.Url.Segments.Length - 1];
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalBLOB"].ConnectionString);
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "select image from BLOBTest where imgId='" + imgId + "'";
// store our Command to be later retrieved by EndProcessRequest
context.Items.Add("cmd", cmd);
// start async DB read
return cmd.BeginExecuteReader(cb, context,
CommandBehavior.SequentialAccess | // doesn't load whole column into memory
CommandBehavior.SingleRow | // performance improve since we only want one row
CommandBehavior.CloseConnection); // close connection immediately after read
}
catch (Exception exc)
{
// will return an image with the error text
this.renderError(context, "ERROR: " + exc.Message);
context.Response.StatusCode = 500;
context.Response.End();
// just to avoid compilation errors
throw;
}
}
/// <summary>
/// Provides an end method for an asynchronous process.
/// </summary>
/// <param name="result">An IAsyncResult that contains information about the status of the process.</param>
public void EndProcessRequest(IAsyncResult result)
{
HttpContext context = (HttpContext)result.AsyncState;
try
{
// restore used Command
SqlCommand cmd = (SqlCommand)context.Items["cmd"];
// retrieve result
using (SqlDataReader reader = cmd.EndExecuteReader(result))
{
this.renderImage(context, reader);
}
}
catch (Exception exc)
{
// will return an image with the error text
this.renderError(context, "ERROR: " + exc.Message);
context.Response.StatusCode = 500;
}
}
#endregion
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
// should never get called
throw new Exception("The method or operation is not implemented.");
}
#endregion
/// <summary>
/// Render a BLOB field to the Response stream as JPEG
/// </summary>
/// <param name="context">HttpContext of current request</param>
/// <param name="myReader">open SqlDataReader to read BLOB from</param>
private void renderImage(HttpContext context, SqlDataReader myReader)
{
// Size of the BLOB buffer.
const int bufferSize = 1024;
long startIndex = 0;
byte[] outbyte = new byte[bufferSize];
long retval;
myReader.Read();
context.Response.Clear();
context.Response.ContentType = "image/jpeg";
do
{
retval = myReader.GetBytes(0, startIndex, outbyte, 0, bufferSize);
// reposition the start index
startIndex += bufferSize;
// output buffer
context.Response.BinaryWrite(outbyte);
context.Response.Flush();
} while (retval == bufferSize);
}
/// <summary>
/// Renders an Error image
/// </summary>
/// <param name="context">HttpContext of current request</param>
/// <param name="msg">message text to render</param>
private void renderError(HttpContext context, string msg)
{
context.Response.Clear();
context.Response.ContentType = "image/jpeg";
// calculate the image width by message length
Bitmap bitmap = new Bitmap(7 * msg.Length, 30);
Graphics g = Graphics.FromImage(bitmap);
// create a background filler
g.FillRectangle(new SolidBrush(Color.DarkRed), 0, 0, bitmap.Width, bitmap.Height);
// draw our message
g.DrawString(msg, new Font("Tahoma", 10, FontStyle.Bold), new SolidBrush(Color.White), new PointF(5, 5));
// stream it to the output
bitmap.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
I know this is a very late reply but maybe this may help some other guys.
I hope your Connection String has asynchronous processing=true.
Also you need to add a content disposition header in your RenderImage function.
finally after the do while loop add a
Context.Response.End()
call.