A Boilerplate HttpHandler
I've been writing HttpHandlers lately for such things as Check Images and Statement Downloads. Remember, an HttpHandler is the kind of thing you want to use when an HttpRequest is going to return a file or image to the browser. Basically anything other than a standard page. True, you could use a page, remove all the HTML from the ASPX part, and return stuff in Page_Load, but that's not really what pages are for, right? Also, Pages are themselves an HttpHandler (returned by PageHandlerFactory) so why not write your own HttpHandler?
Here's a boilerplate template I like to use for an HttpHandler. IMHO, an HttpHandler should always return appropriate HTTP Status Codes like you see below. Make sure the semantics of the status code(s) you choose match what you're trying to express. 404 for Not Found, 403 for Forbidden, 500 for Holy Crap!, etc.
One day I'll be more organized and make an abstract base class to handle this kind of boilerplate stuff. For now, it's on my blog.
1 public class MyHandler : IHttpHandler
2 {
3 private const string CONSTSOMEPARAM = "SomeParam";
4
5 public MyHandler(){}
6
7 public void ProcessRequest(HttpContext context)
8 {
9 // Don't allow this response to be cached by the browser.
10 // Note, you MIGHT want to allow it to be cached, depending on what you're doing.
11 context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
12 context.Response.Cache.SetNoStore();
13 context.Response.Cache.SetExpires(DateTime.MinValue);
14
15 if (ValidateParameters(context) == false)
16 {
17 //Internal Server Error
18 context.Response.StatusCode = 500;
19 context.Response.End();
20 return;
21 }
22
23 if (context.User.Identity.IsAuthenticated == false)
24 {
25 //Forbidden
26 context.Response.StatusCode = 403;
27 context.Response.End();
28 return;
29 }
30
31 string someParam = context.Request.QueryString[CONSTSOMEPARAM];
32
33 SomethingReponse response = SomeService.SomeImportantThing(someParam);
34 if(response.Header == null || response.Header.Success == false)
35 {
36 //Whatever wasn't found
37 context.Response.StatusCode = 404;
38 context.Response.End();
39 return;
40 }
41
42 context.Response.ContentType = "somespecific/mimetype";
43
44 context.Response.BinaryWrite();
45 //or
46 context.Response.Write();
47 //or
48 context.Response.WriteFile();
49 //or
50 someImageStream.Save(context.Response.OutputStream);
51 }
52
53 public bool ValidateParameters(HttpContext context)
54 {
55 //Validate some stuff...true if cool, false if not
56 return false;
57 }
58
59 /// <summary>
60 /// True if this handler can be reused between calls. That's cool if you don't have any class instance data.
61 /// False if you'd rather get a fresh one.
62 /// </summary>
63 public bool IsReusable
64 {
65 get
66 {
67 return true;
68 }
69 }
70 }
HttpHandlers are nice because their endpoint (fancy word for URL) is configurable in your web.config.
<httpHandlers><add verb="GET,POST,WHATEVER" path="SomeEndPoint.ashx" type="MyNamespace.MtHandler, MyAssemblyName" />
</httpHandlers>
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
http://www.jtleigh.com/people/colin/blog/archives/2004/10/copysourceashtm.html
I have been doing a bit with Handlers and enjoyed reading your post. Have you ever used:
<%@ WebHandler Class="ContentWeb.Content" %>
inside of an .ashx file. Where "ContentWeb.Content" is the namespace.name of you class. No need to create an entry in the config file.
-Andrew
* To change the endpoint, you have to rename the file.
* They don't compile until you hit them
* No easy syntax highlighting
* They expose your source if you deploy them outside your company
But they are nice for quick-and-dirty stuff.
As for ASHX, you can choose to put the code in an entirely separate .cs file and only have the <WebHandler> declaration in your .ashx file. That addresses the concerns you listed.
I generally use .ashx in all cases except when the file extension is important (for example, if I need to handle any url for a particular file type).
I use a CLEAR tag (or something like it) and also multiple remove verb, but nothing works. It's a problem with my .Text and any other applications under it, trying to look for the .Text httpmodule assembly, which is obviously not in their own /bin/ directory.
I'm having trouble with showing a 404 error page. Using exactly the same code. All I get is a blank page. Anyone else had this problem and know how to fix it?????
Thanks
M
Comments are closed.
How do you generate the pretty code blocks in your posts?
Thanks-
-EAB