I came across an interesting blog posting and comment today doing some research on ASP.NET performance.  Essentially, Alik Levin mentions that if you're loading images dynamically (either from a file-system or DB) you will not be taking advantage of browser/client caching out-of-the-box.  I'm using a very simple HTTP Handler in one of my applications, the handler, well, handles serving up images in my application - something there are lots of.  So it seems like it makes a lot of sense to have the browser handle caching of these images.

The source code for my entire HTTP Handler looks like this (sorry C# folks):

<%@ WebHandler Language="VB" Class="Image" %>
Imports System
Imports System.Web
Imports System.Web.HttpRequest
 
Public Class Image : Implements IHttpHandler  
 
    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        Dim empID As Integer = Decrypt(Request.QueryString, "EmployeeID")
        If (empID = Nothing) Then Return
       
        Dim Photo As Employee.EmpPhoto
        Photo = Employee.GetPhotoByEmployeeID(empID) 
        
        With EmployeePhoto
            context.Response.ContentType = .ContentType
            context.Response.BinaryWrite(.Data)
        End With
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property
 
End Class

Christopher Lewis mentioned that you can easily add the appropriate cache header to your server's response by a few lines of code to your logic.  Complete code below with comments, note lines 17-27...

   1: <%@ WebHandler Language="VB" Class="Image" %>
   2: Imports System
   3: Imports System.Web
   4: Imports System.Web.HttpRequest
   5:  
   6: Public Class Image : Implements IHttpHandler  
   7:  
   8:     Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
   9:         Dim empID As Integer = Decrypt(Request.QueryString, "EmployeeID")
  10:         If (empID = Nothing) Then Return
  11:        
  12:         Dim Photo As Employee.EmpPhoto
  13:         Photo = Employee.GetPhotoByEmployeeID(empID) 
  14:         
  15:         With EmployeePhoto
  16:             context.Response.ContentType = .ContentType
  17:             'Add below lines to set cache header per Christopher's suggestions
  18:             context.Response.AddFileDependency(imageFileName)
  19:             context.Response.Cache.SetETagFromFileDependencies()
  20:             context.Response.Cache.SetLastModifiedFromFileDependencies()
  21:             context.Response.Cache.SetCacheability(HttpCacheability.[Public])
  22:             context.Response.Cache.SetExpires(DateTime.Now.AddTicks(600))
  23:             context.Response.Cache.SetMaxAge(999)
  24:             context.Response.Cache.SetSlidingExpiration(True)
  25:             context.Response.Cache.SetValidUntilExpires(True)
  26:             context.Response.Cache.VaryByParams("*") = True
  27:             'End added lines
  28:             context.Response.BinaryWrite(.Data)
  29:         End With
  30:     End Sub
  31:  
  32:     Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
  33:         Get
  34:             Return False
  35:         End Get
  36:     End Property
  37:  
  38: End Class

Learn somethin' new everyday :)

Technorati Tags: ,