Accessing Session State in an HttpModule in MVC


Overview

HttpModules can be very useful for a lot of tasks. They are especially handy when trying to accomplish logging within a .NET web application. However, they also come with quite a few hurtles to overcome. In this article we’ll discuss some of those challenges as well as ways to get around them. In the end we will have an HttpModule which can access the session state in order to log the information it contains.

During normal development we typically place our code at a place in the life cycle of the application where everything has been setup and all the resources we need are available. However, in an HttpModule we are dealing with the entire life cycle of an ASP.NET/MVC application. Therefore as resources are setup and torn down, we could find our code having access to very little, depending on which event we register it to serve (see complete life cycle below).

ASP.NET Life Cycle

In order to get access to the session and to be able to log as much as possible, we will be concerning ourselves with 3 events within the life cycle.

  • PreRequestHandlerExecute
  • ProcessRequest (of IHttpHandler)
  • PostRequestHandlerExecute

Generally, most of the code you write (controllers, other methods, etc.) will execute within the MvcHttpHandler, which executes during the ProcessRequest portion of the life cycle. For the purposes of getting access to the pipeline at the point at which the session is available, we will be placing our code in the PreRequestHandlerExecute method.

Creating an HttpModule

An HttpModule is simply a class which inherits from IHttpModule and which has been registered in the web.config.

  1. Create a new class, which we’ll call LogRequests.
  2. Update the class definition to inherit from IHttpModule.
    public class LogRequests : IHttpModule
  3. Create a method to handle the module’s initialization
    public void Init(HttpApplication httpApp) { }
  4. Write a dispose method.
    public void Dispose() { }

Registering HttpModule

We will now register the module in the web.config. Registering the module subscribes it to request-pipeline notifications. This allows it to fire events based on the events that occur within the pipeline. The registration process is slightly different depending on your IIS version and configuration. Using IIS 6.0 or IIS 7.0 Classic Mode allows you to customize requests for resources that are serviced by ASP.NET. However, IIS 7.0+ Integrated mode allows you to customize requests for any resources that IIS serves. This includes HTML files, graphic files and so on.

IIS 6.0 or IIS 7.0 Classic Mode

Place the following tag  in the web.config file within the section shown.

<configuration>
<system.web>
<httpModules>
<add name="LogRequests" type="YourNameSpace.LogRequests"/>
</httpModules>
</system.web>
</configuration>

IIS 7.0 Integrated Mode

Place the following tag  in the web.config file within the section shown.

<configuration>
<system.webServer>
<modules>
<add name="LogRequests" type="YourNameSpace.LogRequests"/>
</modules>
</system.webServer>
</configuration>

Accessing the Events

Now that we have a basic, functional HttpModule setup and registered to receive pipeline notices, let’s actually capture an event, so that we can log something. In order to capture the session we will need to have our code fire during a very specific portion of the life cycle. We will only have access from the PreRequestHandlerExecute event to the PostRequestHandlerExecute event. In this case we will be using the PreRequestHandlerExecute event.

  1. Create a method to contain the code that will execute when the event fires.
    public void OnPreRequestHandlerExecute(Object sender, EventArgs e) { }
  2. Add an event handler within the Init() method to register the new method to the event.
    httpApp.PreRequestHandlerExecute += new EventHandler(this.OnPreRequestHandlerExecute);
  3. Add code within the Init() method, below the event handler, to set the session state behavior to read-only.
    httpApp.Context.SetSessionStateBehavior(SessionStateBehavior.ReadOnly);

Logging Session Info

Now that the hard work is out of the way, let’s actually get access to the session so we can log it somewhere. This code will all go within the OnPreRequestHandlerExecute method we created.

  1. Get access to the HttpApplication.
    var httpApp = (HttpApplication)sender;
  2. Test to be sure the information we need is present.
    if (httpApp == null || httpApp.Request == null)
        return;
  3. Utilize request or other information in whatever way you like.
    httpApp.Request.RawUrl -- Full URL
    httpApp.Request.HttpMethod -- GET or POST
    httpApp.Request.IsAuthenticated -- Authenticated (T/F)
    httpApp.Request.LogonUserIdentity.AuthenticationType -- Auth Type
    httpApp.Request.LogonUserIdentity.Name -- User Name
    httpApp.Request.LogonUserIdentity.IsAnonymous -- Anonymous (T/F)
    httpApp.Request.LogonUserIdentity.IsGuest -- Guest (T/F)
    httpApp.Request.LogonUserIdentity.IsSystem -- System (T/F)
    httpApp.Request.IsLocal -- Localhost (T/F)
    httpApp.Request.IsSecureConnection -- HTTPS (T/F)
    httpApp.Request.UserHostName -- Host Name
    -- httpApp.Request.Browser.* -- Browser Info
    httpApp.Session.SessionID -- Session ID
    httpApp.Session.* -- Other Session Info
    

Summary

That’s it! You now have access to log application information, session information and a lot more, all from within your own HttpModule! I hope this helps others out. If you have any questions or comments, please feel free to leave a comment below.

Reference – ASP.NET Life Cycle

Our code creates an event handler for event 14 below. However, you could create handlers for whatever event you want by repeating the Access the Events section above for a different event below.

  1. Validate the request, which examines the information sent by the browser and determines whether it contains potentially malicious markup. For more information, see ValidateRequest and Script Exploits Overview.
  2. Perform URL mapping, if any URLs have been configured in the UrlMappingsSection section of the Web.config file.
  3. Raise the BeginRequest event.
  4. Raise the AuthenticateRequest event.
  5. Raise the PostAuthenticateRequest event.
  6. Raise the AuthorizeRequest event.
  7. Raise the PostAuthorizeRequest event.
  8. Raise the ResolveRequestCache event.
  9. Raise the PostResolveRequestCache event.
  10. Raise the MapRequestHandler event. An appropriate handler is selected based on the file-name extension of the requested resource. The handler can be a native-code module such as the IIS 7.0 StaticFileModule or a managed-code module such as the PageHandlerFactory class (which handles .aspx files).
  11. Raise the PostMapRequestHandler event.
  12. Raise the AcquireRequestState event.
  13. Raise the PostAcquireRequestState event.
  14. Raise the PreRequestHandlerExecute event.
  15. Call the ProcessRequest method (or the asynchronous version IHttpAsyncHandler.BeginProcessRequest) of the appropriate IHttpHandler class for the request. For example, if the request is for a page, the current page instance handles the request.
  16. Raise the PostRequestHandlerExecute event.
  17. Raise the ReleaseRequestState event.
  18. Raise the PostReleaseRequestState event.
  19. Perform response filtering if the Filter property is defined.
  20. Raise the UpdateRequestCache event.
  21. Raise the PostUpdateRequestCache event.
  22. Raise the LogRequest event.
  23. Raise the PostLogRequest event.
  24. Raise the EndRequest event.
  25. Raise the PreSendRequestHeaders event.
  26. Raise the PreSendRequestContent event.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s