BLOB Reading via IHttpAsyncHandler

1.2k views Asked by At

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);
}
1

There are 1 answers

0
Pankaj Kumar On

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.

 context.Response.AddHeader("Content-Disposition", "attachment; filename=imagefilename.extension");

finally after the do while loop add a Context.Response.End() call.