Click here to Skip to main content
Click here to Skip to main content

Exploring Web.config - system.web/httpModules

By , 18 Apr 2010
 

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 environment 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 interdependencies 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 underpriveleged 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 interdependencies are self evident.

Descriptions are not meant to be authoritative, only generally descriptive.

A full explanation 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

  1. BeginRequest
  2. AuthenticateRequest
    1. System.Web.Security.WindowsAuthenticationModule
      - Uses thread identity and sets User on Context
    2. System.Web.Security.FormsAuthenticationModule
      - Uses forms ticket and sets User on Context
    3. System.Web.Security.PassportAuthenticationModule
      - Similar to forms but not worth the effort to examine in further detail
    4. System.Web.Handlers.ScriptModule
      - Sets Context.SkipAuthorization = true If application is null (?), the request is for a script resource or request is for AuthenticationService
  3. PostAuthenticateRequest
    1. System.Web.Security.RoleManagerModule
      - Discovers roles from cookie or Roles and replaces Context.User Principal with a RolePrincipal
    2. System.Web.Security.AnonymousIdentificationModule
      - Manages an anonymous identifier for unauthenticated requests/sessions
    3. System.ServiceModel.Activation.HttpModule
      - Seems to be an internal wrapper/placeholder for services. Usage is not clear to me at this time.
  4. AuthorizeRequest
    1. 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.
    2. System.Web.Security.FileAuthorizationModule
      - checks ntfs permissions and sets 401 if fail.
  5. PostAuthorizeRequest
  6. ResolveRequestCache
    1. System.Web.Caching.OutputCacheModule
      - Checks cache policy against request to determine whether to serve cached content.
  7. PostResolveRequestCache
  8. MapRequestHandler
  9. PostMapRequestHandler
  10. AcquireRequestState
    1. System.Web.SessionState.SessionStateModule
      - Hydrates session
    2. System.Web.Profile.ProfileModule
      - Sets Profile on Context
  11. PostAcquireRequestState
    1. System.Web.Handlers.ScriptModule
      - Executes 'PageMethods'.
  12. PreRequestHandlerExecute
  13. PostRequestHandlerExecute
  14. ReleaseRequestState
    1. System.Web.SessionState.SessionStateModule
      - Removes session from context
  15. PostReleaseRequestState
  16. UpdateRequestCache
    1. System.Web.Caching.OutputCacheModule
      - Checks cache policy against response to determine whether to cache content.
  17. PostUpdateRequestCache
  18. EndRequest
    1. System.Web.SessionState.SessionStateModule
      - Updates session items timeout.
    2. System.Web.Security.FormsAuthenticationModule
      - If request status 401 and not on login page (via very ugly kludge) redirects to login page.
    3. System.Web.Security.PassportAuthenticationModule
      - Similar to forms but not worth the effort to examine in further detail.
    4. System.Web.Security.RoleManagerModule
      - Updates role cookie if RolePrinicipal roles have changed since PostAuthenticate
    5. System.Web.Profile.ProfileModule
      - Updates Profile store from Context if AutoSaveEnabled
    6. System.Web.Handlers.ScriptModule
      - catches AsyncPostBackError, clears response and writes out text/plain error message
  19. PreSendRequestHeaders
    1. System.Web.Handlers.ScriptModule- Handles 302 (redirects). For AsyncPostBackRequests the cookies are transferred to a new text/plain redirect message and for RestRequests ('application/json') a 401 is set with json text content.
  20. 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sky Sanders
Software Developer (Senior) Salient Solutions
United States United States
Member
My name is Sky Sanders and I am an end-to-end, front-to-back software solutions architect with more than 20 years experience in IT infrastructure and software development, the last 10 years being focused primarily on the Microsoft .NET platform.
 
My motto is 'I solve problems.' and I am currently available for hire.
 
I can be contacted at sky.sanders@gmail.com

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionInteresting article but... [modified]memberCarl Reid25 Aug '09 - 23:16 
Thanks for the article. This is a very interesting topic (for me at least since I am in the middle of writing a single sign on system and am making use of a number of these http modules). However, could you provide an explanation of what you feel a solution for the problem of 401/403 errors being raised in the wrong order is.
 
"Faulty logic. Should be replaced with more discriminative code that differentiates a 401 from a 403."
 
EDIT: Just found another article by you talking about this: http://www.codeproject.com/Articles/39062/Salient-Web-Security-AccessControlModule.aspx[^]
 
Perhaps you should link the two together?
 
Also, it might be an idea to talk about how the events are raised in Global.asax. The fact that the event name is a concatenation of the module name, underscore and then method. I always felt this area of .NET to be badly explained in the documentation and a bit "auto-magical". Also the fact that the events handlers are hooked up using reflection still suprises me!
 
Thanks
 
modified on Wednesday, August 26, 2009 5:23 AM

AnswerRe: Interesting article but...memberSky Sanders26 Aug '09 - 0:33 
Carl, I feel your pain.
A lot of the momentum for this and the access control modules comes from my experiences building forms auth based SSO that aggregate discreet credential silos of all types via a config based plugin architecture.
 
As you found, my answer to forms auth bungling of 403 is addressed in the access control module. The salient feature there is the correct implementation of custom error pages for 403 that allow you to come to a complete stop as gracefully as you wish without kludging the login page to detect underpriveledged access.
 
You can find a post; about a preliminary iteration of the access control module that might provide a bit more background.
 
Perhaps you should link the two together?

Sounds like a good idea.
 
r.e. global events: the only real topic in this context is how configurable httpmodules let you take your configuration out of the codebehind. I do not recommend applying systemic logic in global for anything more than the most trivial applications.
 
In any case, I hope you find some value in the posts and thanks for the feedback.
GeneralRe: Interesting article but...memberCarl Reid26 Aug '09 - 2:20 
Thanks for the link, I have read the article and the update it points to. Great approach to the problem. I have downloaded the demo and will be going through it when I have a min. Many thanks again!
 
To get around the problem I have always checked the url, querystring and the HTTP referrer previoulsy to determine an authorisation problem which as you state "feels dirty". It also amazes me that MS have not fixed this but raises a big question re ASP.NET in general.
 
cue rant....
.NET appears to be like an onion, each new release adding more layers wrapped around the previous ones but no changes to anything that was already there. Whist I appreciate making sweeping changes would of course break an awful lot of existing code, we cannot simply continue with code which was written years ago and contains countless unresolved bugs . Surely it's time to release a new framework which sits on its own and addresses a lot of the existing issues. A great example of this is the System.Messaging assembly - it was written to use MSMQ 3 - since then we have version 4 and 5 but this assembly only works against the version 3 api since it never changes in new releases!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 18 Apr 2010
Article Copyright 2009 by Sky Sanders
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid