To our second installment on this two part series on handlers and modules in ASP.NET web applications, their significance and how to begin debugging situations where things have gone haywire. Like I mentioned in the previous post on handlers: modules and handlers go together like peas and carrots. The main difference is the following: whereas a handler runs only when ASP.NET has decided it should handle the incoming request and ASP.NET stops after it has found the handler, the module always runs on every request and ASP.NET continues. So the way that looks is that upon a web request ASP.NET first passes the request to each and every module in the list of modules and then tries to find a handler for it and passes the request on. Most crucially a module can alter a request as it passes through it or set the stage for other components before they run. For the remainder of this post I assume you will have seen/read through the previous post and you are familiar with Fiddler, web requests and responses and IIS 6 and 7 differences in the web.config.
Below is the modules section (IIS 7) of a default DNN site.
If you’re interested look up one of these in the source code and see what it does. Did you know that:
- DNN’s Url rewrite module also initializes PortalSettings
- DNN’s membership module takes care of user login, roles, authentication cookies, and user language
Basics of an http module
A module can flag to ASP.NET to be kicked into action at the beginning and/or the end of a request. ASP.NET hands control over to the module and it can look at the request, and change it (at begin request) or the response (typically at end request). A common example of the former is url rewriting. A Url rewiter changes the url at the beginning of the request. Url rewriters are used to make web urls more human friendly and get better results in search engines. Lets take the example of a request that asks for resource “/Blog/ThisWonderfullBlogpost.aspx”. By analyzing the resource string and looking things up in a database the url rewriter is now able to deduce that this is a request for page id 3 and blog post id 18. It then substitutes the found values and the request continues its journey in ASP.NET as “/Default.aspx?tabid=3&itemid=18” for instance. Another common example of logic in a module that fires at the beginning of a request is to add variables and their values to the application property bag. These can later be used by the application. An example of this is the variable PortalSettings which holds all the current DotNetNuke’s portal settings in an object. This way subsequent processing doesn’t need to recreate those all the time. Instead they are present throughout the request to both the DNN main application as well as the extensions.
An example of a module that latches on to the end of processing is a compressor. A compressor changes the response (output) of the server by running it through for instance a GZip compression component.
If you want to find out more about http modules check out the various web resources about these and/or examine the DotNetNuke source code for some great examples.
Errors in modules lead to different symptoms than errors in handlers. A routing issue with handlers usually breaks stuff immediately. A module failure can hide itself better. But the approach in debugging is still similar to what was mentioned in the handlers post. We start by examining the web traffic for hidden error messages and routing issues. We also should not forget to look at the DNN event log to see if we spot exceptions that have come out of a module. It helps at this point to have a rough idea of what each module does.
A special mention here about upload components. There are a number of upload components (Telerik, ComponentArt, NeatUpload, etc) that use Ajax callbacks to stream an upload to the server. What the component does is chunk the file that is being uploaded into small bits and upload one by one using Ajax and using the server’s responses to drive a progress bar/indicator. This has several advantages, notably user feedback and better memory management on the server. Typically these upload components use a module to get the stream of uploaded bytes. So when debugging upload issues, check out the modules in the web.config and make sure the necessary one is there and running (failed request tracing as described in the previous post can help you see running modules as well). Try removing non-essential ones to see if this helps. I have witnessed one upload component “eat” the bytes destined for the right upload component before it got to it which led to failed uploads as the upload component that had consumed the upload didn’t know what to do with it and the expecting upload component was left empty handed.
As mentioned before you need to use your knowledge of IIS (in these two posts), the application and Google to work your way through any issue with handlers and modules. It is a skill which you’ll develop and you’ll come to appreciate. Due to the nature of DotNetNuke extension programming, a developer cannot guarantee that all goes well. The configuration is not under our control and it is impossible to foresee what happens in the future. These two posts hope to help you cover some ground in this respect.