Managing IIS Pipeline Mode for Backward Compatibility
Ever since the induction of IIS 7, there came a cool new feature for developers to leverage called Integrated Pipeline. This feature in a short explanation closely couples ASP.NET and IIS more closely. It allows allows writing of IIS Modules in managed code, how neat is that? This also slightly changes the behavior of ASP.NET, such as introducing new events on the HttpApplication (Global.asax) and the event cycle. A classic example is where in Integrated mode you cannot access the current request using HttpContext.Current.Request during theApplication_Start event, which makes sense.
Now for obvious reasons this can break existing applications, and cannot be used for applications that will be installed in mixed environments, such as Server 2003 and Server 2008. Fortunately, IIS 7 make it easy to switch it back back to its old behavior using the Classic Pipeline by configuring the IIS AppPool. Most commonly, if you make a web-based product then your application will usually require Classic Pipeline to stay backwards compatible.
Even if you have a detailed instruction manual, this can be an easy step to miss - and results in some icky error messages. Wouldn't it be nice if you could display an nice error message to your customers that their pipeline is configured improperly?
Well fortunately there is a way to do that. Ironically, we will be using part of the Integrated Pipeline to get that accomplished with the help of an HttpModule.
What we will be doing is writing an HttpModule that will basically stop the current request, write out a friendly message that links to a Knowledge Base article, and only do this if our application is running in Integrated Pipeline. The module to get this done is pretty simple, we would write it like any other HttpModule. Here is the code for mine:
using System;
using System.Web;
namespace MyWebApplication
{
public sealed class IisPiplineCheckModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}
private void context_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.WriteFile(VirtualPathUtility.ToAbsolute("~/pipeline.htm"));
HttpContext.Current.Response.End();
}
public void Dispose()
{
}
}
}
As you can see, there is nothing particularly difficult. It just hooks into the BeginRequest event of the Application, and writes a file called pipeline.htm to the response stream and closes the response. Pretty simple, right?
Well the final trick is getting this to work only in Integrated Pipeline. Unusually, there is no easy way to do this with the .NET Framework (that I was able to find). However we will leverage the web.config to accomplish this.
For IIS 7, there is a new section in the web.config file called. This is one of the sections that IIS 7 pays attention to. What we will do is introduce our module into IIS 7's Integrated Pipeline, but not into the old that has been existing for a long time. Let's look at our new section and examine it.
There are two interesting points here. The first is actually adding out module. Notice the preCondition. This is telling IIS 7 that our module should only be running in Integrated Pipeline by specifying the integratedMode flag. For the Type we just set the full namespace and class to our HttpModule and the assembly it is located in.
The second interesting point is that if you have standard HttpModules registered in the configuration/system.web/httpModules section IIS 7 will point out that there are modules in there that are not in the system.webServer configuration. We can, if we want, disable that through the validation element.
And ta-da, we now have a module that writes out a file, but only for Integrated Pipeline. You can customize the pipeline.htm file as much as you'd like. As far as I can tell, this is the only easy way to determine if your application is in Integrated or Classic Pipeline. The alternative is to WMI query the IIS metabase, which is a little more high risk and more complex.
Now for obvious reasons this can break existing applications, and cannot be used for applications that will be installed in mixed environments, such as Server 2003 and Server 2008. Fortunately, IIS 7 make it easy to switch it back back to its old behavior using the Classic Pipeline by configuring the IIS AppPool. Most commonly, if you make a web-based product then your application will usually require Classic Pipeline to stay backwards compatible.
Even if you have a detailed instruction manual, this can be an easy step to miss - and results in some icky error messages. Wouldn't it be nice if you could display an nice error message to your customers that their pipeline is configured improperly?
Well fortunately there is a way to do that. Ironically, we will be using part of the Integrated Pipeline to get that accomplished with the help of an HttpModule.
What we will be doing is writing an HttpModule that will basically stop the current request, write out a friendly message that links to a Knowledge Base article, and only do this if our application is running in Integrated Pipeline. The module to get this done is pretty simple, we would write it like any other HttpModule. Here is the code for mine:
using System;
using System.Web;
namespace MyWebApplication
{
public sealed class IisPiplineCheckModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}
private void context_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.WriteFile(VirtualPathUtility.ToAbsolute("~/pipeline.htm"));
HttpContext.Current.Response.End();
}
public void Dispose()
{
}
}
}
As you can see, there is nothing particularly difficult. It just hooks into the BeginRequest event of the Application, and writes a file called pipeline.htm to the response stream and closes the response. Pretty simple, right?
Well the final trick is getting this to work only in Integrated Pipeline. Unusually, there is no easy way to do this with the .NET Framework (that I was able to find). However we will leverage the web.config to accomplish this.
For IIS 7, there is a new section in the web.config file called
There are two interesting points here. The first is actually adding out module. Notice the preCondition. This is telling IIS 7 that our module should only be running in Integrated Pipeline by specifying the integratedMode flag. For the Type we just set the full namespace and class to our HttpModule and the assembly it is located in.
The second interesting point is that if you have standard HttpModules registered in the configuration/system.web/httpModules section IIS 7 will point out that there are modules in there that are not in the system.webServer configuration. We can, if we want, disable that through the validation element.
And ta-da, we now have a module that writes out a file, but only for Integrated Pipeline. You can customize the pipeline.htm file as much as you'd like. As far as I can tell, this is the only easy way to determine if your application is in Integrated or Classic Pipeline. The alternative is to WMI query the IIS metabase, which is a little more high risk and more complex.
Comments
Post a Comment