2

Hey all I have been working to get my 20+ thumbnails into a cache state so it doesn't always going the server to get the images each time the page is loaded/reloaded.

I have implemented the "eTag" into my response call like so:

var uriFetcher = new UriFetcher(fileUri);
var tempPath = uriFetcher.FetchFile();
var mime = MimeType(tempPath);

//displays like: xxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.png
//This is the image file name. These names do not change.
string theETag = tempPath.Split('\\').Last();

context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetLastModified(DateTime.Now);
context.Response.Cache.SetValidUntilExpires(true);
context.Response.Cache.SetExpires(DateTime.Now.AddYears(1));
context.Response.Cache.SetMaxAge(new TimeSpan(1, 0, 0));
context.Response.CacheControl = "private";
context.Response.ContentType = mime;

//Add current image file name to the eTag
context.Response.AddHeader("ETag", "\"" + theETag + "\"");

var disposition = new ContentDisposition
{
    FileName = Path.GetFileName(tempPath),
    Inline = mime.Contains("image")
};

context.Response.AddHeader("content-disposition", disposition.ToString());

try {
   context.Response.TransmitFile(tempPath);
} catch {
   context.Response.TransmitFile(errorUri);
}

Now after the .cs part above it goes to a JavaScript function that's using the jQuery framework in order to place it onto the page for the user to see:

var imgThumbnail = img('thumbnail', '/' + thumbnailId + '/Thumbnail', preload)
    .tipsy({
        html: true,
        assetMode: false,
        fallback: assetData.Tooltip.html(),
        gravity: ($container.closest('#Side').length == 0) ? $.fn.tipsy.auto : 'e',
        topOffset: topOffset
    });
if (assetData.ProcessingRollupStatus != null) {
    if (assetData.ProcessingRollupStatus === 'Processing') {
        imgThumbnail.addClass('processing-status-processing');
    } else if (assetData.ProcessingRollupStatus === 'Waiting') {
        imgThumbnail.addClass('processing-status-waiting');
    }
}

$container
    .addClass('asset-item')
    .data('AssetData', assetData)
    .attr('id', assetData.Id)
    .append(imgThumbnail);

And from Firefox this is what the output looks like:

enter image description here

enter image description here

So the part where I am having issues is when I go check for the eTag when the page is loaded/refreshed. I'm not really sure what (or where) I should put that code in order for it to not load the images if they are already in cache?

I was thinking something like this:

var requestedETag = context.Request.Headers["If-None-Match"];

if (requestedETag == last)
{
    return new HttpStatusCodeResult(HttpStatusCode.NotModified);
    //context.Result = new StatusCodeResult(304);
} else {
   ...........

So, anyone care to enlighten me as to how to go about doing this check?

StealthRT
  • 10,108
  • 40
  • 183
  • 342

1 Answers1

0

I believe I found the correct way of doing this:

var uriFetcher    = new UriFetcher(fileUri);
var tempPath      = uriFetcher.FetchFile();
var mime          = MimeType(tempPath);
string imgName    = tempPath.Split('\\').Last();
var requestedETag = context.Request.Headers["If-None-Match"];

if (requestedETag != imgName && requestedETag != null)
{
    context.Response.StatusCode = 304;
    context.Response.StatusDescription = "Not Modified";
}
else
{
   var disposition = new ContentDisposition
   {
       FileName = Path.GetFileName(tempPath),
       Inline   = mime.Contains("image")
   };

   context.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
   context.Response.Cache.SetLastModified(DateTime.Now);
   context.Response.Cache.SetValidUntilExpires(true);
   context.Response.Cache.SetExpires(DateTime.Now.AddYears(1));
   context.Response.Cache.SetMaxAge(new TimeSpan(1, 0, 0));
   context.Response.CacheControl = "private";
   context.Response.ContentType = mime;
   context.Response.AddHeader("ETag", "\"" + imgName + "\"");
   context.Response.AddHeader("content-disposition", disposition.ToString());

   try
   {
      context.Response.TransmitFile(tempPath);
   }
   catch
   {
      context.Response.TransmitFile(errorUri);
   }
}

In the first time load of the particular page it defines the eTag that is the unique name that the image has (imgName). The unique image name would be something like iAmAnImage123.png for an example.

If the user refreshes the page it then goes into the "If-None-Match" check which has the unique image name. This is being compared to the current image eTag name that is being loaded.

In my case I went from loading 1 MB each time the user loaded/refreshed the page:

enter image description here

to just 1 MB at first then only 158.80 KB thereafter. An 835.80 KB savings!:

enter image description here

So basically it looks like this when its at the If statement above:

 |-> Question: Hey has iAmAnImage123.png already been loaded before? 
  |-> Yes: Well then, skip it and pass a 304 to the browser to let them know that
           its already been cached then go on to the next image. 
  |-> No: Alright, lets load it and then remember it by adding a unique eTag to
          it which we will be calling it iAmAImage123.png.
StealthRT
  • 10,108
  • 40
  • 183
  • 342