IIS7 modules vs. IIS6 ISAPI: Managing request state in your module

For post #4 in the IIS7 Modules vs. IIS6 ISAPI series, let's take a look at another common pattern in IIS module development - storing request-specific state inside your module.

When developing a module that participates in request processing, it is often necessary to store request-specific state that the module computes in one stage of the pipeline, and then uses again in a later stage.  For example, if you are writing a module that calcuates the duration of the request, you will need to capture the initial timestamp at the beginning of the pipeline, and then compare it with the timestamp at the end of request processing in order to determine how long the request took.

At a high level, in order to do this, the module needs to allocate some memory to store the state, and associate it with the particular request.  In subsequent request pipeline stages, it needs to look it up, and eventually, deallocate the memory used to store it when the request is finished.

If you just want to see how this is done with IIS7 module APIs, jump straight to the IIS7 part.

Let's first see what is involved when using IIS6 ISAPI filters.

In the ISAPI filter world, each request notification is delivered to the ISAPI DLL via the static HttpFilterProc entrypoint function, passing along the notification id and the filter context structure: 

DWORD WINAPI HttpFilterProc(
  PHTTP_FILTER_CONTEXT pfc,
  DWORD NotificationType,
  LPVOID pvNotification
);


Then, depending on the notification, your HttpFilterProc implementation will provide the required request processing.  In our case, what we are interested in is to store some information, such as our timestamp, during an early notification such as SF_NOTIFY_PREPROC_HEADERS, and then access it later in a late notification such as SF_NOTIFY_END_OF_REQUEST

First, some basics - because your ISAPI filter will be notified separately for the different notifications, you cannot store the state in a local variable inside a function.  Also, since the ISAPI filter will be responsible for processing many requests concurrently, you cannot simply store the state in a static variable inside your DLL.  Instead, you must either:

  1. Create your own table indexed by the request being processed, and store/lookup state in that table, providing the proper locking to insure thread safety. (DONT DO THIS Smile)
  2. Use the server-provided mechanism to associate your own state "context" object with the request, and use it to keep your state between notifications.  This context is automatically associated with the current request, and provided to your filter during each notification inside the HTTP_FILTER_CONTEXT structure.

Our code would look something like this:

class CMyContext

{

public:

    CMyContext(clock_t time)

        : startTime( time )

    {

    }

       

    clock_t GetStartTime()

    {

        return startTime;

    }

       

private:

    clock_t startTime;

};

 

DWORD

WINAPI

HttpFilterProc(

   PHTTP_FILTER_CONTEXT pfc,

   DWORD notificationType,

   LPVOID pvNotification

)

{

    CMyContext*             pContext = NULL;

    clock_t                 time;

       

    switch(notificationType)

    {

    case SF_NOTIFY_PREPROC_HEADERS:

        time = clock();

       

        //

        //  Create and store our per-request context instance

        //

        pfc->pFilterContext = new CMyContext(time);

        break;

    case SF_NOTIFY_END_OF_REQUEST:

       

        //

        //  Get the context from the filter

        //

        pContext = (CMyContext *)pfc->pFilterContext;

        time = clock() - pContext->GetStartTime();

       

        //

        //  Clean up the context at the end of the request

        //

        delete pContext;

        pfc->pFilterContext = NULL;

       

        break;

    default:

        break;

    }

       

    return SF_STATUS_REQ_NEXT_NOTIFICATION;

}

 


Some notes about this code:

  1. I had to create my own context class, CMyContext, to store the request state data I need.
  2. I have to allocate the context for each request, and then make sure to clean it up at the end of the request to avoid memory leaks (alternatively, I could have used the the request memory pool that doesnt need deallocation by allocating the memory with the AllocMem filter support function).

Now, lets take a look at how IIS7 does it

In IIS7, the server will create a new instance of your module class for each request (see this post for more explanation of the IIS7 module class).  Because of this, storing request state is as simple as declaring member variables inside your module class.  You can set the values of these variables as you compute the state during one or more notifications, and use them directly from other notifications.

With this in mind, your IIS7 code looks like this:

class CMyModule : public CHttpModule

{

public:

    CMyModule()

        : startTime ( 0 )

    {

    }

       

    REQUEST_NOTIFICATION_STATUS

    OnBeginRequest(

        IN IHttpContext *                       pHttpContext,

        IN OUT IHttpEventProvider *             pProvider

    )

    {

        startTime = clock();

       

        return RQ_NOTIFICATION_CONTINUE;

    }

       

    REQUEST_NOTIFICATION_STATUS

    OnEndRequest(

        IN IHttpContext *                       pHttpContext,

        IN OUT IHttpEventProvider *             pProvider

    )

    {

        clock_t elapsed = clock() - startTime;

       

        return RQ_NOTIFICATION_CONTINUE;

    }

       

private:

    clock_t     startTime;

};


This eliminates the need to create a separate state class, and associate it with he request via an external mechanism.  You can declare and use all of the request state as type-safe member variables directly inside your module.

Because there is only one thread processing a single request at any given time, and there is a separate instance of your module for each request, you don't need to worry about thread safety (as long as you are using instance variables).

When the request is finished, your CHttpModule instance is automaticaly cleaned up by the server, so you dont need to worry about managing the lifetime of the state.  Just make sure to release whatever resources you are using inside your module's destructor like you normally would for any C++ class.

What about non-request state?

Sometimes, you will need to store state that is not associated with a particular request.  This is necessary whenever the lifetime of the state extends beyond the request, or is scoped to a particular server object like connection, application, or an arbitrary url - for example, in order to keep track of the number of requests to a particular site.  IIS7 provides a mechanism to do this by associating your own context (sorry, extra class required) with the object of choice via the IHttpModuleContextContainer inteface avaialble from many server objects. 

More on this in a future post ...  
 

Published 25 December 06 05:50 by Mike Volodarsky
Filed under: , ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Bett said on May 4, 2007 5:22 AM:
These are all great comments and suggestions (and more are welcome). Thanks. I will follow up as soon as I can.
# Torquemada said on May 5, 2007 1:42 PM:
Regarding the open-source "rules", have you considered releasing the models under a Creative Commons license?
# c0ld said on May 6, 2007 1:07 AM:
Regarding the open-source "rules", have you considered releasing the models under a Creative Commons license? Buy tenuate . Buy levitra . Drugs info online Buy meridia . in gamlet Buy zithromax and Sheriff Buy xenadrine Buy levitra Buy meridia Buy zyban Buy zithromax Buy zithromax Buy xenadrine Buy tenuate Buy levitra Buy xenadrine Buy cialis Buy xenadrine Buy xenadrine Buy zyban Buy tenuate Buy valtrex Buy meridia Buy cialis ... This site: [url=http://buycialis20mg.easyjournal.com]order cialis[/url] and [url=http://meridiavip.easyjournal.com]order meridia[/url] - no [url=http://buyxenadrine.easyjournal.com]order xenadrine[/url] http://zithromaxvip.easyjournal.com. In pharmastore Buy zithromax . Overnight delivery Buy xenadrine Buy levitra Buy meridia Buy zyban Buy zithromax Buy zithromax Buy xenadrine Buy tenuate Buy levitra Buy xenadrine Buy cialis Buy xenadrine Buy xenadrine Buy zyban Buy tenuate Buy valtrex Buy meridia Buy cialis .

Leave a Comment

(required) 
(optional)
(required) 
Enter the code you see below


About Mike Volodarsky

For the past 5 years, I was the core Program Manager for Microsoft ASP.NET 2.0 and IIS 7.0 products. I drove the design and development of the IIS 7.0 web server core, the IIS FastCGI support, the AppCmd command line tool, the ASP.NET Integrated pipeline, and other special projects around server security, performance, and scalability. Now, I am working on my own on cutting edge web server tech on top of the Microsoft IIS platform, and continue blogging about it here.

About me



For the past 5 years, I was the core server Program Manager for the IIS 7.0 and ASP.NET 2.0 products at Microsoft.
Now, I work on advanced web server tech using IIS 7.0, .NET, and Windows Server 2008 and write about it in this blog.

View Michael Volodarsky's profile on LinkedIn

Writings



TechNet Magazine
>Top 10 Performance Improvements in IIS 7.0

MSDN Magazine
>IIS 7.0: Build Web Server Solutions with End-To-End Extensibility
>IIS 7.0: Enhance Your Apps with the Integrated ASP.NET Pipeline
>IIS 7.0: Explore The Web Server For Windows Vista And Beyond
>Design and Deploy Secure Web Apps with ASP.NET 2.0 and IIS 6.0
>Fast, Scalable, and Secure Session State Management for Your Web Applications


Tools and Modules

LeechGuard
IconHandler 2.0
DirectoryListing
HttpRedirection
IIS Auth for Wordpress
iisschema.exe
PortCheck.exe v2.0

Popular Posts

- ASP.NET 2.0 Breaking Changes on IIS 7.0
- Develop IIS7 modules and handlers with .NET
- Troubleshoot IIS7 errors like a pro
- Troubleshooting 503 / "service unavailable" errors
- Troubleshooting "server not found" errors
- Create IIS7 sites, applications, and virtual directories
- Run Ruby on Rails with IIS FastCGI
- VS Debugging of ASP.NET applications on Windows Vista
- Stop hot-linking with IIS and ASP.NET

Tags

Search

Go

This Blog

Archives

Good IIS Blogs

Disclaimer

These postings are provided as is with no warranties, and confer no rights. The views expressed in this blog are entirely my own.

Syndication