[Note: I use the term web application in this post. This is not the Visual Studio 'Web Application' but rather refers to any .NET content that runs under IIS.]
Application pools, on the surface, look to be a wonderful addition to IIS 6.0. However, unless you have a good understanding of how application pools work with regard the .NET framework, you could end up causing some serious damage. This is something that is usually explained in literature, but the impact of it is typically glossed over, so I’m here to help fill the gap.
Application pools are a way to allow web application isolation on a web server. An application pool is just a container for a worker process (w3wp.exe), which is in charge of serving requests for all the applications that it manages. A single application pools can have multiple worker processes running under it (termed a web garden), but a single worker process cannot run across multiple pools. An application pool can, theoretically, manage an infinite amount of applications, but you also have the ability to create more than one, and you can assign your application to any available pool using the IIS console (or programmatically).
Application pools create isolation in the sense that if there is a failure in one pool (the w3wp.exe process dies), it will not affect the other pools that are running. These failures occur at times, and in the case of web servers that serve multiple web sites, isolation is key – you don’t want your site to go down because someone else killed your worker process. Application pools also have the ability to run under different user credentials, which means you can manage access to certain resources using application pools. Application pools are also agnostic of .NET framework version – the virtual directory is the item that dictates both what
application pool manages it, and the version of the framework that it runs under. You assign an application to an application pool using IIS console.
One strange, and potentially dangerous, thing about application pools is that they can only run one version of the .NET framework at once. This
means that if you try serving an application that runs under .NET 1.1 and another under .NET 2.0 simultaneously, then they had better be under different application pools. What happens if you try running both at the same time? The first application that gets served will work, regardless of the framework version it runs under. The second will fail, and all subsequent requests for either application will fail. The worker process ends up dying an untimely death. How is this an issue? Well here are two very likely scenarios where this behavior can cause problems:
- A user has just added a new virtual directory and has not been diligent on choosing the correct application pool
- A web application has been upgraded to a newer version of the .NET framework, and the user updates the framework version on the virtual directory but fails to change to a more appropriate application pool.
So, how does one mitigate risk of application pool failure under this scenario? One of the most important things to do is to make sure you have
at least one application pool for every framework version that your web server supports. Typically, I do this by including the framework version in
the application pool name, for example naming two pools ‘ExamplePool 1.1′ and ‘ExamplePool 2.0.’ This greatly simplifies management. A good way to
see what version of an application pool that you are running under is to open the IIS console and expand the tree node that corresponds to the pool
you are interested in. This will allow you to see what applications are running under a given pool.
There are other options available to mitigate the risks of this issue hurting you, but all have significant drawbacks. First, you could create a
different application pool for every application you run. For a few applications this is fine. However, since each pool contains a w3wp.exe
process, a large number of active pools could slow down your server. Second, you could leverage a w3wp.exe process ping that will restart failed
processes. The drawback here is that this only works on one-off instances: a real issue will continuously kill the w3wp.exe process very quickly after
it is restarted. A third option is that you could make sure your application does not target a particular .NET framework version (they are supposedly pretty compatible, but there can be breaking changes from time to time). However, this means that you had the time to test your existing codebase before you introduce a new framework version. The only solution that I’ve found to work is pure diligence.