Adding your own httpHandler to Sitecore 5.3

As you all know, Sitecore has customized the whole ASP.NET framework a little for own proposes. Sometimes this does mean that you have to take a little more actions to get some stuff done. Today I’m going to show you how we can create a cool .ashx. I’m going to generate some extreme cool circles ;).
You properly can do this without following all the steps below and do it how it should be done, but you won’t have a fully initialized Sitecore-context in that case.

First I’ve to think about the url I want to access the httpHandler.
Note: Like Sitecore does with its media and icons, I do recommend to start your url with a tilde(~). The ASP.NET-engine does recognize the tilde as the root, so both the following urls will give you the same page:
http://yoursite.ext/~/media/mypicture.ashx
http://yoursite.ext/something/~/media/mypicture.ashx

My url for generating those cool circle should become:
http://localhost/~/generation/images/cirkel.ashx

Then I’ve to decide how it should be rewritten internal. Media-urls will be rewritten to sitecore_media.ashx inside Sitecore, Icons become sitecore_icons.ashx, etc. I’ll use ‘custom_imagegen.ashx’.

Now we’ve to configure this. First we setup the nice url. Therefor we’ve to open the web.config. Then you’ve to search for the node ‘customHandlers’ under the ‘sitecore’-node. Then add another customHandler like I’ve done below:

    <customHandlers>

      <handler trigger=~/media/ handler=sitecore_media.ashx />

      <handler trigger=~/api/ handler=sitecore_api.ashx />

      <handler trigger=~/rest/ handler=sitecore_rest.ashx />

      <handler trigger=~/xaml/ handler=sitecore_xaml.ashx />

      <handler trigger=~/icon/ handler=sitecore_icon.ashx />

      <handler trigger=~/generation/images/ handler=custom_imagegen.ashx />

    </customHandlers>

Then the we’ve to configure the httpHandler under the ‘system.web’-node:

    <httpHandlers>

      <add verb=* path=sitecore_media.ashx type=Sitecore.Resources.Media.MediaRequestHandler, Sitecore.Kernel />

      <add verb=* path=sitecore_rest.ashx type=Sitecore.Web.UI.XamlSharp.Ajax.RestPageHandlerFactory, Sitecore.Kernel />

      <add verb=* path=sitecore_xaml.ashx type=Sitecore.Web.UI.XamlSharp.Xaml.XamlPageHandlerFactory, Sitecore.Kernel />

      <add verb=* path=sitecore_icon.ashx type=Sitecore.Resources.IconRequestHandler, Sitecore.Kernel />

      <add verb=* path=custom_imagegen.ashx type=Sitecore.TestSite.ImageGenerator, Sitecore.TestSite />

    </httpHandlers>

As you can see, I’ve configured a class to the handler. Make sure the class implements System.Web.IHttpHandler and its members.
I’ve created the following demonstration class to test if my configuration works:

    1     public class ImageGenerator : IHttpHandler

    2     {

    3         #region IHttpHandler Members

    4 

    5         public bool IsReusable

    6         {

    7             get { return true; }

    8         }

    9 

   10         public void ProcessRequest(HttpContext context)

   11         {

   12             context.Response.Write(context.Request.RawUrl);

   13         }

   14 

   15         #endregion

   16     }

After building the solution it becomes time to test my implementation. Let’s try: http://localhost/~/generation/images/cirkel.ashx. And as expected, the page returns:

/~/generation/images/cirkel.ashx

Note: Make sure you set ‘IsReusable’ to true as it indicates weather the system can reuse the instance of the class for another request.
Alright, so that seems to work! Now it’s time to create a cool circle generator…

    1     public class ImageGenerator2 : IHttpHandler

    2     {

    3         #region Field(-s)

    4         public int DefaultAlpha

    5         {

    6             get

    7             {

    8                 return 80;

    9             }

   10         }

   11         public Color DefaultColor

   12         {

   13             get

   14             {

   15                 return Color.Red;

   16             }

   17         }

   18         public Size DefaultSize

   19         {

   20             get

   21             {

   22                 return new Size(200, 200);

   23             }

   24         }

   25         public int QueryStringAlpha

   26         {

   27             get

   28             {

   29                 return GetIntFromQueryString(“alpha”, DefaultAlpha, 255);

   30             }

   31         }

   32 

   33         public Color QueryStringColor

   34         {

   35             get

   36             {

   37                 return Color.FromArgb(GetIntFromQueryString(“c”, DefaultColor.ToArgb(), 2000));

   38             }

   39         }

   40         public Size QueryStringSize

   41         {

   42             get

   43             {

   44                 return new Size(GetIntFromQueryString(“w”, DefaultSize.Width, 2000), GetIntFromQueryString(“h”, DefaultSize.Height, 2000));

   45             }

   46         }

   47         #endregion

   48 

   49         #region IHttpHandler Members

   50         public bool IsReusable

   51         {

   52             get { return true; }

   53         }

   54 

   55         public void ProcessRequest(HttpContext context)

   56         {

   57             WriteResponseHeader(context);

   58 

   59             using (Bitmap myImg = new Bitmap(QueryStringSize.Width, QueryStringSize.Height))

   60             {

   61                 DrawOnBitmap(myImg);

   62 

   63                 MemoryStream ms = new MemoryStream();

   64                 myImg.Save(ms, ImageFormat.Png);

   65                 ms.WriteTo(context.Response.OutputStream);

   66             }

   67         }

   68         #endregion

   69 

   70         #region Protected Members

   71         protected void WriteResponseHeader(HttpContext context)

   72         {

   73             context.Response.ClearHeaders();

   74             context.Response.AddHeader(“Content-Type”, “image/png”);

   75             context.Response.AddHeader(“Content-Transfer-Encoding”, “binary”);

   76             context.Response.CacheControl = “public”;

   77         }

   78 

   79         protected void DrawOnBitmap(Bitmap image)

   80         {

   81             Rectangle rect = new Rectangle(Point.Empty, QueryStringSize);

   82 

   83             //Hack to make sure the Ellipse fits in my Image

   84             rect.Width–;

   85             rect.Height–;

   86 

   87             using (Graphics g = Graphics.FromImage(image))

   88             {

   89                 g.SmoothingMode = SmoothingMode.AntiAlias;

   90                 Color c = Color.FromArgb(QueryStringAlpha, QueryStringColor.R, QueryStringColor.G, QueryStringColor.B);

   91 

   92                 g.DrawEllipse(new Pen(c), rect);

   93                 g.FillEllipse(new SolidBrush(c), rect);

   94             }

   95         }

   96         #endregion

   97 

   98         #region Private Static Helper(-s)

   99         private static int GetIntFromQueryString(string key, int defaultValue, int maxValue)

  100         {

  101             string qsValue = HttpContext.Current.Request.QueryString[key];

  102             int resultValue;

  103 

  104             if (!string.IsNullOrEmpty(qsValue) && int.TryParse(qsValue, out resultValue) && resultValue <= maxValue)

  105             {

  106                 return resultValue;

  107             }

  108             return defaultValue;

  109         }

  110         #endregion

  111     }

Playing around with the options described above showed me that /~/media/ is hardcoded in a lot of Sitecore-code. That’s a pity. Hopefully one of the developers will pick this up and fix it in the next build.

One thought on “Adding your own httpHandler to Sitecore 5.3”

Comments are closed.