Streaming Databased Images Using HttpHandler
Asked Answered
U

3

4

For a long time now I have noticed something annoying when working on Web Application projects involving databased images on my local machine. By local I mean that it's a typical environment with VS 2008 and SQL Server 2005 on my workstation. Whenever I use an HttpHandler to display the images on my local, only some of the images render on each page load.

However, when I push the application to a hosted environment, the problem usually disappears. However, I just pushed a new project out to a hosted environment and experienced the same problem as on my local - this time the site and the DB were on the same server in the hosting environment. Has anyone got a take on what's happening here?

Here's the handler:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class FeaturedHandler : IHttpHandler
{
    Business biz = new Business();

    public void ProcessRequest(HttpContext context)
    {
        if (context.Request.QueryString["ListingID"] != null)
        {
            int listingID = Convert.ToInt32(context.Request.QueryString["ListingID"]);

            DataSet ds = biz.GetFeaturedImageByID(listingID);
            DataRow row = ds.Tables[0].Rows[0];
            byte[] featureImage = (byte[])row["Photo"];
            context.Response.ContentType = "image/jpeg";
            context.Response.OutputStream.Write(featureImage, 0, featureImage.Length);
        }
        else
            throw new ArgumentException("No ListingID parameter specified");
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
} 

I have tried using a DB on a separate server but encountered the same problem. Should I be using a DataReader instead?

UPDATE I should have used a DataReader initially since I am reading binary data.

Unicycle answered 2/10, 2009 at 3:7 Comment(1)
Might be related: #5501450Fabiolafabiolas
U
4

I finally got all images to render by changing the value of the IsReusable property to true:

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }

Apparently, this keeps the handler in memory and able to handle multiple requests. When set to false, it had to create a new instance of the handler for each incoming request.

Unicycle answered 9/10, 2009 at 3:26 Comment(3)
Doh! I can't believe we missed that. I always set "IsReusable" to true. I didn't even look at it in your code. Congrats on finding a solution.Highstepper
I'd really like to know how setting "IsReusable" to true helps in this case. Shouldn't a new handler always be able to serve the image? The example here is streaming dynamically sized images and is setting "IsReusable" to false: c-sharpcorner.com/UploadFile/desaijm/…Killer
Could never find proper documentation on MSDN for this property and could only observe through testing...Unicycle
T
3

By this:

Whenever I use an HttpHandler to display the images on my local, only a portion of the images render on each page load.

Do you mean that the same image appear on places where different images should appear or that some images appear and some doesn't show at all?

In your case the difference by switching isReusable to true is that new Business(); will be called once for multiple images. If isReusable is false the new Business(); will be called once per image. This means that if you have several images per page new Business(); will be called several times for this particular page.

Also I strongly suggest changing this:

if (context.Request.QueryString["ListingID"] != null)
{
    int listingID = Convert.ToInt32(context.Request.QueryString["ListingID"]);

with:

string listingIdParam = context.Request.QueryString["ListingID"];
if (listingIdParam != null)
{
    int listingID = Convert.ToInt32(listingIdParam);

This will save you null reference exceptions that usually surface only under heavy load. Also the above will prevent serving the wrong image to a request especially when isReusable is true.

I cannot determine what the problem was exactly but I can definitely say that setting the isReusable flag was just a workaround and doesn't fix your problem. Also when a problem like this is reproducible only in certain environment that means that either it's a thread problem or there is some difference in request handling (different web server - IIS6, IIS7, development server).

Maybe posting the Business class and it's constructor can shed some light. Also I suggest implementing some kind of error logging to trap exceptions in the handler and review them.

Truck answered 31/3, 2011 at 15:13 Comment(2)
Great input Branislav. Some of the pics wouldn't render at all. Tonight I will search for the original code and post it here, thanks :)Unicycle
Branislav, I looked up the code. Apparently, I eliminated the call to the business class when I swapped out the DataSet for a DataReader - makes more sense for reading binary data? I wrote the SQL query inline. This seems to have solved the problem.Unicycle
F
0

If you are serving images directly, do not forget to set the correct caching headers, i.e. etags and expires. If you don't you are really going to hit your database hard and use up your bandwidth.

You will need to handle the following http headers:

  • ETag
  • Expires
  • Last-Modified
  • If-Match
  • If-None-Match
  • If-Modified-Since
  • If-Unmodified-Since
  • Unless-Modified-Since

For an example http handler that does this check out: http://code.google.com/p/talifun-web/wiki/StaticFileHandler

Filly answered 22/2, 2010 at 10:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.