download this document in .doc form
HttpApplication Events, the HttpModules that handle them and in what order:
It is a generally held opinion that to depend upon the order of module/event execution is bad practice and produces brittle code. I agree somewhat with the spirit of the opinion but not at all with the explicit reason.
Events and Collections are not magic bags that arbitrarily insert handlers/items in some random order. I think, in a general sense, that to depend on event handler execution order is a 'bad idea' is valid. In a more specific context, in which the enviroment is known and tightly controlled, the argument loses a bit of weight.
It is evident from reading the source for the built-in modules compared to the order that they are added to the collection that the calling order of initialization and application event handlers in registered HttpModules is entirely dependant on the order in which they are added to the HttpModules collection.
There are, as illustrated below, sequential inter-dependancies in the execution logic of the built-in modules.
I believe that, in order to write custom modules that are affected by or intend to affect the execution of built-in modules, you must understand and may depend on the order of execution of the built-in modules and event handlers.
The primary argument against this is that the possibility of configuration change renders your sequentially dependant code brittle. I find that argument specious (yes, I am talking to you Rick ;-))
If someone finds the need to go into the root web config file and fundamentally alter the behaviour of the ASP.NET runtime in a way that leaves an aftermarket module incompatible or faulty, how does that indicate brittle code in the module?
It smells like a simple requirements/compatibility issue to me. How the module author states requirements and handles the absence of those requirements is another issue entirely.
Listings follow that are the result of a reflector dive and reflection wrapper binge I did in the interest of improving the behavior of FormsAuthentication in regards to non-authenticated versus under-priveledged access to a resource.
Any corrections or improvements are completely welcome.
Listing 1: Default httpModules sections
<!-- the root web configuration file -->
<configuration>
<system.web>
<httpModules>
<add name="OutputCache" type="System.Web.Caching.OutputCacheModule"/>
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
<add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule"/>
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"/>
<add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule"/>
<add name="RoleManager" type="System.Web.Security.RoleManagerModule"/>
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule"/>
<add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule"/>
<add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule"/>
<add name="Profile" type="System.Web.Profile.ProfileModule"/>
<add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</httpModules>
</system.web>
</configuration>
<!-- asp.net 3.5 application web configuration file -->
<configuration>
<system.web>
<httpModules>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</httpModules>
</system.web>
</configuration>
Event handlers described below are executed only if the module/mode is enabled/valid. The sequential interdependancies are self evident.
Descriptions are not meant to be authoritive, only generally descriptive.
A full explaination of the Application lifecycle can be found @ http://msdn.microsoft.com/en-us/library/ms178473.aspx and Reflector can be found @ http://www.red-gate.com/products/reflector/.
Listing 2: Sequenced Pipeline Events
- BeginRequest
- AuthenticateRequest
- System.Web.Security.WindowsAuthenticationModule
- Uses thread identity and sets User on Context.
- System.Web.Security.FormsAuthenticationModule
- Uses forms ticket and sets User on Context.
- System.Web.Security.PassportAuthenticationModule
- Similar to forms but not worth the effort to examine in further detail.
- System.Web.Handlers.ScriptModule
- Sets Context.SkipAuthorization = true If application is null (?), the request is for a script resource or request is for AuthenticationService.
- PostAuthenticateRequest
- System.Web.Security.RoleManagerModule
- Discovers roles from cookie or Roles and replaces Context.User Principal with a RolePrincipal
- System.Web.Security.AnonymousIdentificationModule
- Manages an anonymous identifier for unauthenticated requests/sessions.
- System.ServiceModel.Activation.HttpModule
- Seems to be an internal wrapper/placeholder for services. Usage is not clear to me at this time.
- AuthorizeRequest
- System.Web.Security.UrlAuthorizationModule
- if context.SkipAuthorization is false checks permissions and sets 401 if fail. Faulty logic. Should be replaced with more discriminative code that differentiates a 401 from a 403.
- System.Web.Security.FileAuthorizationModule
- checks ntfs permissions and sets 401 if fail.
- PostAuthorizeRequest
- ResolveRequestCache
- System.Web.Caching.OutputCacheModule
- Checks cache policy against request to determine whether to serve cached content.
- PostResolveRequestCache
- MapRequestHandler
- PostMapRequestHandler
- AcquireRequestState
- System.Web.SessionState.SessionStateModule
- Hydrates session.
- System.Web.Profile.ProfileModule
- Sets Profile on Context.
- PostAcquireRequestState
- System.Web.Handlers.ScriptModule
- Executes 'PageMethods'.
- PreRequestHandlerExecute
- PostRequestHandlerExecute
- ReleaseRequestState
- System.Web.SessionState.SessionStateModule
- Removes session from context.
- PostReleaseRequestState
- UpdateRequestCache
- System.Web.Caching.OutputCacheModule
- Checks cache policy against response to determine whether to cache content.
- PostUpdateRequestCache
- EndRequest
- System.Web.SessionState.SessionStateModule
- Updates session items timeout.
- System.Web.Security.FormsAuthenticationModule
- If request status 401 and not on login page (via very ugly kludge) redirects to login page.
- System.Web.Security.PassportAuthenticationModule
- Similar to forms but not worth the effort to examine in further detail.
- System.Web.Security.RoleManagerModule
- Updates role cookie if RolePrinicipal roles have changed since PostAuthenticate.
- System.Web.Profile.ProfileModule
- Updates Profile store from Context if AutoSaveEnabled.
- System.Web.Handlers.ScriptModule
- catches AsyncPostBackError, clears response and writes out text/plain error message.
- PreSendRequestHeaders
- System.Web.Handlers.ScriptModule
- Handles 302 (redirects). For AsyncPostBackRequests the cookies are transfered to a new text/plain redirect message and for RestRequests ('application/json') a 401 is set with json text content.
- PreSendRequestContent
Conclusion
Understanding the application pipeline and request lifecycle will demystify a great deal of what happens and why in between the time a url is entered and content is served. It can also make you more effective at writing code that capably influences the request lifecycle.
It is not black magic nor is it insanely complex or undiscoverable. Get a copy of Reflector and find out for yourself.
Technorati tags:
ASP.NET,
HttpModule,
CodeProject