Tuesday, February 3, 2015

Microsoft 70-486: Design HTTP modules and handlers

Exam Objectives


Implement synchronous and asynchronous modules and handlers, choose between modules and handlers in IIS

Quick Overview of Training Materials


How To Create an ASP.NET HTTP Handler by Using Visual C# .NET
Writing asynchronous HTTP Module in ASP.NET 4.5

My post on WebSockets

Implementing modules and handlers


In order to get a better handle (no pun intended) on what exactly httpModules do and how they operate, I started out by attempting the "How to" described on MSDN.  While it was a decent start, it didn't work right off the bat, probably owing to the fact that the article is over 10 years old (sigh, epic fail on my part).  But the gist of it was right, once I got the web.config settings in the right place.  The following code is what I ended up with:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
 
namespace MobileWebApplication.Models
{
    public class TestModule : IHttpModule
    {
        public void Dispose() { }
 
        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(OnBeginRequest);
            context.EndRequest += new EventHandler(OnEndRequest);
        }
 
        public void OnBeginRequest(Object s, EventArgs e)
        {
            HttpApplication app = s as HttpApplication;
            app.Context.Response.Write("Hello from OnBeginRequest in test module. <br>");
        }
 
        public void OnEndRequest(Object s, EventArgs e)
        {
            HttpApplication app = s as HttpApplication;
            app.Context.Response.Write("Hello from OnEndRequest in test module. <br>");
        }
    }
}

This is the correct web.config setting.  I left the validation and handler stuff the way I found it and added this after:
  <system.webServer>
    ...
    <modules>
      <add name="TestModule" type="MobileWebApplication.Models.TestModule, MobileWebApplication"/>
    </modules>
  </system.webServer>

This is what it looked like when rendered.  I commented out all the jQuery Mobile stuff I had in there before, which is why it's so plain, but this way it's easier to see where the module events did their thing:

The Init method of IHttpModule fires when the application is first starting up.  For me, it consistently executed three time, though I suspect this was just wonkiness with the debugger or something.  The point is, it does not execute for every page load.  The event handlers, on the other hand, will fire every time the appropriate events are fired, in this case at the beginning and end of every request.  I was curious about what was going on with the context when Init was being called, so I took a peek with a breakpoint.  There were a total of 18 modules loaded, the last three of which were all "Dynamic Modules" (which led me to this post on David Ebbo's blog...)


The HttpApplication class defines something like 26 events that can be subscribed to in the Init function.  In addition to the two shown above, I played with RequestCompleted, PreRequestHandlerExecute, and PreSendRequestContent.  PreRequestHandlerExecute fired immediately after BeginRequest, and PreSendRequestContent fired immediately after EndRequest.  RequestCompleted fired last, but because by the time it fired everything had been disposed of, I could no longer write to the response.  Not all the requests are related to the timing of the http life cycle.  Caching, logging, auth, and state all have relevant events.

One thing I found online is several graphics depicting modules as these layers that every request and response pass through, which gives the distinct impression that modules do stuff with each request both ways.  I find this to actually be a less than helpful way of thinking of it, because while modules CAN manipulate requests as they come it, it's not like the request gets passed to every single module.  The request generates events as part of its life cycle, which can trigger actions by modules.  So I drew my own version of this interaction.  Unless I seriously missed the boat, I think this is closer to what is happening:


The Exam Ref points out that using an asynchronous module can have certain advantages, which are largely the same benefits we expect when using async methods generally: that is, the main thread isn't blocked while some long running module process is completing, and if the module thread bombs, the rest of the request processing can continue.  A module that accesses the file system, or a database, or a web service, are all potential use cases.  One caveat pointed out in the Exam Ref is that, should the processing of the request depend on the outcome of an asynchronous module, you could end up with a race condition if you aren't careful, which again just speaks to appropriate use of async.  Brock Allen's post touches on the nuances of the different API's (the older APM style which uses "Begin" and "End" callbacks) as well as the newer .NET 4.5 model which uses Task, await, and async.  The codeproject article also offers up some .NET 4.5 style code (you just have to muscle past a bit of broken English, due respect to the author lol).

An HttpHandler serves as an endpoint for a web requests.  In my post on websockets, I followed an example of a Generic Handler class that implemented IHttpHandler to service websockets requests.  Several types of HttpHandlers are already included in the .NET framework.  The websocket example had the file extension .ashx; the ASP.NET Page handler deals with .aspx files; the web service handler serves .asmx files.  Other file extensions can be assigned to a handler by registering them in the web.config file.  The acceptable Http verbs are also set when registering a new handler.

Handlers can be made asyncronous by inheriting from the HttpTaskAsyncHandler, which provides the Task based ProcessRequestAsync method.  Alternatively, the handler can implement the IHttpAsyncHandler interface, which includes the BeginProcessRequest and EndProcessRequest methods (similar to the APM style described in Brock Allen's post on asynchronous modules).

Choosing Between Handler and Module


Choosing between a module and a handler can be quite easy at times.  Many of the examples of their respective use are pretty clear cut.  Processing a websockets request requires a handler; authenticating all incoming requests needs to use a module.  Special handling for requests to a .rss file makes sense in a handler.

One interesting example from the Exam Ref is the case of adding a watermark to an image.  This could be handled by either a handler for image files that adds the watermark, or by having a module intercept image resources and add the watermark.

Handlers and Modules are fundamentally very different.  Whereas a single handler is called in response to a request for a specific resource, modules react to events that are fired from the request pipeline.  Choosing which to use should be an exercise in recognizing what it is you are trying to accomplish and matching the appropriate tool to that need (which is pretty much true of how you handle EVERY programming problem, ey?)

No comments:

Post a Comment