IIS 7.0

Build Web Server Solutions with End-To-End Extensibility

Mike Volodarsky

This article discusses:
  • IIS extension points
  • Building a Response Modification module
  • Adding IIS Manager configuration
  • Deploying the module
This article uses the following technologies:
IIS 7.0, .NET Framework

Contents

Extending the Web Server
A Response Modification Module
Extending Configuration
Response Modification Configuration
A Strongly Typed Configuration Class
Extending IIS Manager
Creating the Service
Creating the Module Page
Deploying the Extension
Tying It All Together
Build Your Own

The IIS 7.0 Web platform supports more application framework technologies for hosting rich applications than any previous version of IIS, and it comes chock-full of features that you can use to deploy these applications right out of the box. At the same time, however, what you see (in Windows® Setup) is not necessarily what you always get.

The IIS 7.0 architecture is designed to be extensible from top to bottom, allowing you to replace any part of the built-in feature set with a custom implementation that suits your needs. As a result, instead of providing a patchwork of plug-in points, IIS 7.0 makes the ultimate commitment to extensibility by implementing all of its own features on top of the public extensibility model. This design is found throughout the platform, from the modular Web server engine itself to the configuration system to the IIS Manager console.

In this article, I'll dive into the IIS 7.0 extensibility model by walking through the shared source Response Modification project, which enables responses from IIS applications to be modified on the fly using configurable response modification rules. I'll first build the Web server module by taking advantage of the server's integrated ASP.NET extensibility. Then, I'll shape the deployment and management features for the module by developing a custom configuration section and creating a custom management page for IIS Manager.

Extending the Web Server

The IIS 7.0 modular architecture offers the ability to completely customize the Web server for a required workload. This can often be done simply by installing only the features needed for your application, yielding a lean Web server that does exactly what is needed and nothing more.

However, this is only the first step. Often, the desired Web workload requires additional functionality that may not be part of the built-in IIS feature set. Or, in some cases, the application may require a customized set of functionality for which the built-in features are not flexible enough. Because all of the IIS 7.0 features are built on public extensibility APIs, you can replace any of them with a custom implementation that best fits your needs.

IIS 7.0 provides two options for developing Web server modules. First, you can use the new C++ module API on which most of the built-in features are based. The module API replaces the ISAPI extension and filter API offered in previous versions of IIS. This API is a significant improvement over ISAPI, as it is rich enough to support all of the IIS 7.0 features and it is significantly easier to program against. You can learn more about the improvements in this API at mvolo.com/blogs/serverside/archive/2006/10/07/10-reasons-why-server-development-is-better-with-IIS7.aspx.

Second, IIS 7.0 features ASP.NET integration, which allows IIS 7.0 modules to be developed by using the familiar ASP.NET module APIs. With ASP.NET Integrated mode, these modules become first-class citizens in the IIS request processing pipeline, as shown in Figure 1. This enables ASP.NET modules to access IIS intrinsic objects, such as the request and response, in all stages of request processing, and to process requests for all resource types—not just those handled by the ASP.NET framework.

Figure 1 ASP.NET Modules in IIS 7.0 Request Processing

Figure 1** ASP.NET Modules in IIS 7.0 Request Processing **(Click the image for a larger view)

This allows powerful ASP.NET features like Forms-based authentication, Login controls, and the Membership service, to be used uniformly for the entire Web site. For an in-depth view of how ASP.NET Integrated mode can be used to add value to existing applications not written for the ASP.NET framework, be sure to read my article in the January 2008 issue of MSDN® Magazine at msdn.microsoft.com/msdnmag/issues/08/01/PHPandIIS7.

For developers, the real value of the ASP.NET Integrated mode is the ability to extend the IIS Web server using the Microsoft® .NET Framework. This brings significant benefits in rapid application development by providing the ability to build on the rich framework support of the .NET Framework, ASP.NET, and other frameworks like the Windows Workflow Foundation.

A Response Modification Module

The ASP.NET Integrated pipeline enables ASP.NET modules to perform a wide variety of tasks during the processing of each request. This wide variety ranges from performing authentication or authorization to modifying the outgoing response before it is sent to the client.

The purpose of the Response Modification module is to do the latter, to allow existing responses to be modified on the fly using a set of replacement rules. To do this, we can leverage the ASP.NET response filtering mechanism, which, thanks to the runtime integration, allows filtering of the outgoing responses for any content, including static files and ASP and PHP scripts.

If you have developed an ASP.NET module in the past, you'll appreciate the fact that you continue to use the same exact APIs to develop ASP.NET modules for IIS 7.0. In fact, your existing modules continue to work the same way as they did in previous versions of IIS (unless you take advantage of IIS 7.0 Integrated mode to run them for all requests). The module is a class that implements the System.Web.IHttpModule interface and registers event handlers for one or more request pipeline events. The Response Modification module is no different:

class ResponseModificationModule : IHttpModule
{
  public void Init(HttpApplication app)
  {
    // Wire up the filter in PreRequestHandlerExecute
    app.PreRequestHandlerExecute += 
      new EventHandler(OnPreRequestHandlerExecute);
  }

  public void OnPreRequestHandlerExecute(
    Object source, EventArgs e)
  {
    ...
  }
}

At its core, the module subscribes to the PreRequestHandlerExecute event, which occurs right before the request handler is executed. The OnPreRequestHandlerExecute method is used to read configuration information to determine whether the response has any applicable replacement rules (more on configuration later in the article), and if so, register a response filter stream that will later be used to filter the outgoing response, as shown in Figure 2.

Figure 2 Response Filter

public void OnPreRequestHandlerExecute(Object source, EventArgs e)
{
  HttpApplication app = (HttpApplication)source;
  HttpContext context = app.Context;

  // Read configuration 
  ResponseModificationConfigurationSection config;
  
  ...

  // Get the list of filters
  ResponseFilterList filters = GetApplicableFilters(context, config);

  // Create the filter and wire it up
  if (null != filters && filters.Count > 0)
  {
    context.Response.Filter = 
      new ChainedBufferedStringResponseFilter(
        context, filters);
  }
}

The response filtering work is done inside the ChainedBufferedStringResponseFilter class, which is responsible for converting the response bytes into a string using the response character set, and invoking one or more response filters that apply to this request. The module associates the filter with the response by setting the HttpResponse.Filter property. This property accepts objects that inherit from the System.IO.Stream abstract class and later uses them to filter the outgoing response entity body.

The ASP.NET response filtering facility is just one of the mechanisms that you can take advantage of when developing ASP.NET modules for IIS 7.0 Integrated mode. You can also rewrite URLs, perform request authentication and authorization, modify or issue cookies and response headers, log the request, and so on. Most of the tasks that previously required native ISAPI development are now possible by simply writing an ASP.NET module. You can find a step-by-step walkthrough of building ASP.NET modules for IIS 7.0, the development environment options, and deployment steps at mvolo.com/blogs/serverside/archive/ 2007/08/15/Developing-IIS7-web-server-features-with-the-.NET-framework.aspx.

When developing an IIS 7.0 module, you can take advantage of a number of IIS features that aid in management and deployment. One of these features is the ability to specify custom module configuration in the IIS 7.0 configuration files, and either have that configuration deployed automatically with the application, or managed with a number of IIS 7.0 administration tools and APIs. Doing this is key to ensuring that the functionality provided by the module can be properly configured and managed by end users.

Extending Configuration

The new configuration system is the foundation for many of the key deployment and management scenarios possible with IIS 7.0. Instead of being a proprietary machine-central configuration store, the IIS 7.0 configuration system is based on structured XML configuration files located in the same configuration files used by the ASP.NET configuration system. Moreover, the syntax of the IIS configuration information is identical to that of the ASP.NET configuration information and can be placed side-by-side in distributed web.config files that ASP.NET developers are already very familiar with and love.

This design opens many doors. First, it allows applications to specify IIS configuration information alongside their application content, which makes them easy to deploy by simply publishing their content to the server. This ensures that the applications work correctly without needing to modify machine-centric configuration information on each server on which they are deployed and also without requiring Administrative privileges on each server. The structured XML configuration format, plus the ability to put ASP.NET configuration together with IIS configuration in a single file, makes it a lot easier for developers to author and manage all IIS-related configuration information. This can be done with an XML editor such as Notepad and Visual Studio® or can be automated by using the configuration APIs provided by the IIS 7.0 administration stack.

The best part about all of this is the fact that the IIS 7.0 configuration system is completely extensible. Allowing custom Web server features to publish configuration that can be set and managed side-by-side with the IIS 7.0 configuration plays a key role in building complete solutions for IIS 7.0.

Unlike the .NET configuration system, adding a new IIS 7.0 configuration section requires no code because all IIS 7.0 configuration sections are themselves defined using an XML-based schema. In fact, all built-in IIS 7.0 configuration sections are defined using this mechanism. You can find the definitions for all IIS configuration sections in the %windir%\system32\inetsrv\config\schema directory in the IIS_Schema.xml file. For example, the <defaultDocument> configuration section, which enables and configures default documents for your application, is defined as follows:

<sectionSchema name="system.webServer/defaultDocument">
  <attribute name="enabled" type="bool" defaultValue="true" />
  <element name="files">
    <collection addElement="add" clearElement="clear" 
      removeElement="remove" mergeAppend="false">
      <attribute name="value" type="string" isUniqueKey="true"/>
    </collection>
  </element>
</sectionSchema>

This schema defines all of the elements and attributes that are part of the configuration section, their types, and additional information such as collection definitions, and attribute validation behavior. To learn more about the syntax of the schema definition, see the comments at the top of the IIS_Schema.xml configuration file.

Response Modification Configuration

The Response Modification module requires its own configuration section in order to configure a number of specific settings, including what filtering rules to enable for the application. To allow this configuration section to be used in the IIS configuration files, you first need to create the schema file describing the structure of the section (see Figure 3). This file defines the responseModification section and its structure, including the enabled attribute and the collection of filter rules that can be configured to invoke filter types with additional information about what to replace and with what to replace it.

Figure 3 Response Modification Configuration Schema

<configSchema>
  <sectionSchema name="responseModification">
    <attribute name="enabled" type="bool" defaultValue="false" />
    <collection addElement="add" clearElement="clear" 
      removeElement="remove">
      <attribute name="name" type="string" required="true" 
        isUniqueKey="true" validationType="nonEmptyString" />
      <attribute name="conditionType" type="string" required="false" />
      <attribute name="condition" type="string" required="false" />
      <attribute name="replaceType" type="string" required="true" 
        validationType="nonEmptyString" />
      <attribute name="replace" type="string" required="false" />
      <attribute name="replaceWith" type="string" required="false" />
      <attribute name="options" type="string" required="false" />
    </collection>
  </sectionSchema>
</configSchema>

To install this configuration section, you need to do two things. First, copy the responsemod_schema.xml file containing the section schema information to the %windir%\system32\inetsrv\config\schema directory. Then declare the configuration section in the server's main configuration file, applicationHost.config. The latter task requires writing some code if you'd like to perform this installation programmatically.

To simplify the process of installing IIS 7.0 configuration sections, I wrote the iisschema.exe tool, which performs both of these tasks automatically. You can get the tool from mvolo.com/blogs/serverside/archive/2007/08/04/IISSCHEMA.EXE-_2D00_-A-tool-to-register-IIS7-configuration-sections.aspx. With this tool, installing the configuration schema section becomes a single-step process:

IisSchema.exe /install responsemod_schema.xml

Now that the configuration section schema is installed and the section itself is declared in applicationHost.config, you can immediately begin using it to define configuration information for the module.

You can use any of the IIS configuration tools or APIs to manage the configuration for this section, just like you would normally do for any of the built-in IIS 7.0 configuration sections. For example, I can enable the Response Modification feature for my application by using AppCmd, the IIS 7.0 command-line tool:

%windir%\system32\inetsrv\AppCmd Set Config "Default Web Site/" 
/section:responseModification  /enabled:true 

I can also add a rule to the rule collection of the responseModification configuration section:

%windir%\system32\inetsrv\AppCmd Set Config "Default Web Site/" 
"/+[name='StripWhitespace',replaceType=
'Mvolo.ResponseModification.Filters.HtmlDeflate']"

If you then open the web.config file in the root of the default Web site (which is typically %windir%\inetpub\wwwroot), you will find the following code:

<configuration>
  <responseModification enabled="true">
    <add name="StripWhitespace" 
      replaceType="Mvolo.ResponseModification.Filters.HtmlDeflate" />
  </responseModification>
</configuration>

If you ever modify the web.config file for the application to change the module's configuration information and then upload it to the server, the application will be configured to use the new settings. Likewise, if you upload the application to another server that has the configuration section installed, you can be sure that the application will use the desired settings without needing to reconfigure it on that server.

In addition to AppCmd, you can now use any of the IIS 7.0 configuration APIs to manage the configuration information for this section, including the managed Microsoft.Web.Administration API, the IIS 7.0 Windows Management Instrumentation (WMI) provider, the IIS 7.0 configuration COM objects, and Windows PowerShell®. In addition to setting and reading this configuration information, you can also perform any management task that is supported by the IIS 7.0 configuration system, including controlling how this section is delegated to applications, protecting its content with configuration encryption, and so on. However, in order for this configuration information to be useful, you need to be able to read it from the Response Modification module.

The Microsoft.Web.Administration API is a new .NET Framework API provided in IIS 7.0 that enables programs to access the IIS 7.0 configuration information. In addition to allowing configuration and setup programs to manage configuration, it is also the API that can be used to read configuration information from within a managed module.

You can use the API to read the configuration section in the module immediately after registering the configuration section because the API exposes a loosely typed model for reading configuration sections. Before you do this, you will need to add a reference to Microsoft.Web.Administration.dll, which is located in the %windir%\system32\inetsrv directory. Note that this DLL is only included with IIS 7.0 on Windows Vista® or Windows Server® 2008 and is not included with the .NET Framework or Windows SDKs.

With the assembly reference added, I can read the module's configuration information:

ConfigurationSection section = 
  WebConfigurationManager.GetSection(
    context, 
    "responseModification");

bool enabled = (bool)section["enabled"];

The WebConfigurationManager class in the Microsoft.Web.Administration namespace is almost identical to WebConfigurationManager in the System.Web.Configuration namespace and is intended to replace the use of the latter for IIS 7.0 managed modules that read IIS 7.0 configuration. The GetSection method retrieves the configuration section object for the current HTTP request path.

A Strongly Typed Configuration Class

The ConfigurationSection object allows loosely typed access to any configuration section without any additional code. You can access the enabled attribute simply by retrieving it by name from the section object's indexer and casting it to the expected type.

However, you can take it one step further by generating a strongly typed wrapper for the configuration section. You can quickly generate the wrapper class by using the tool written by Kanwaljeet Singla, a fellow IIS team member, located at blogs.iis.net/ ksingla/archive/2006/12/04/tool-to-generate-strongly-typed-classes-for-configuration-sections.aspx. This will generate a wrapper class for the section that looks like Figure 4. This class simply wraps the underlying ConfigurationSection class, and provides strongly typed properties to access the underlying configuration data.

Figure 4 Strongly Typed Configuration Section Wrapper

class ResponseModificationSection : ConfigurationSection
{
  public bool Enabled
  {
    get { return (bool)this["enabled"]; }
    set { this["enabled"] = value; }
  }

  public ResponseModificationRuleCollection FilterRules
  {
    get 
    { 
      return (ResponseModificationRuleCollection)
        GetCollection(typeof(ResponseModificationRuleCollection)); 
    }
  }
}

As you can see from the implementation of the Enabled property, wrapping the configuration attributes is straightforward. Wrapping child elements and child collections requires further implementation of wrapper classes that inherit from ConfigurationElement and ConfigurationCollection respectively (not shown), in a similar fashion to the section wrapper itself.

After the wrapper class has been generated, you can compile it into a separate assembly and reference it in your module project or simply add it as a source code file. This will enable the module to access the configuration section in a type-safe way:

ResponseModificationSection section =
  (ResponseModificationSection)WebConfigurationManager.GetSection(
    context, 
    "responseModification", 
    typeof(ResponseModificationSection)
  );

bool enabled = section.Enabled;

Likewise, you can also begin to access the response modification rule collection and the properties on each of the rule elements in a type-safe manner. This makes it a lot easier to program against configuration sections and minimizes the amount of type safety mistakes that are common with weakly typed data access. Also, because all of the code used to access the underlying data is generated automatically by the tool, you can set up Visual Studio to automatically build the wrapper classes from the configuration schema file each time you compile the project. This makes managing changes to the configuration section schema a breeze.

Extending IIS Manager

So far, I have shown you how to create the Response Modification module and enable it to read the custom configuration section that controls its behavior. This configuration can be stored in the same configuration files as the rest of IIS configuration information, can be deployed together with the application in web.config files, and can be managed with a variety of tools and APIs including AppCmd.exe and Microsoft.Web.Administration.

At this point, the Response Modification module can be deployed and properly configured in any IIS environment. However, you can take it one step further by providing a custom management experience for the IIS Manager console. Doing this brings a number of benefits. It allows system administrators to easily configure the module by using the IIS Manager console, without needing to edit configuration files directly or use any of the lower-level tools and APIs. It also allows the module configuration information to be managed using IIS Manager remote administration capabilities, which take advantage of the Web Management Service (WmSvc).

Unlike other tools that also support remote administration, the IIS Manager remote administration architecture offers several key advantages. First, it allows users who are not Administrators on the server to manage sites and applications over which they have control. Second, the IIS Manager remoting mechanism uses HTTPS, instead of DCOM, which is easier to expose through corporate firewalls. Together, these two capabilities make the IIS Manager attractive for delegated remote management of IIS Web sites, especially in shared Web-hosting environments.

In the true spirit of IIS 7.0, the IIS Manager provides an extensible architecture on which most of the built-in IIS Manager features are based. To facilitate the remote management scenario, each management feature consists of two parts: the client-side components that provide the UI experience inside IIS Manager, and the server-side component that provides the actual management services.

The server-side service is loaded inside IIS Manager for local management scenarios or inside the Web Management Service in remote management scenarios. In the latter case, IIS Manager handles the required communication between the components in IIS Manager on the client machine and the service running inside WmSvc on the target server machine.

Creating the Service

The client and server components are typically implemented in two separate .NET assemblies that do not reference each other. All communication between the client and server components is done via the IIS Manager ModuleServiceProxy abstraction that uses weakly typed property bags and basic .NET types to exchange the required information.

The server assembly usually contains an implementation of the Microsoft.Web.Management.Server.ModuleProvider class, which performs the necessary registration of services and client-side Modules, and an implementation of the Microsoft.Web.Management.Server.ModuleService class, which exposes the service methods to perform the required management tasks.

My Mvolo.ResponseModificationUI.Server.dll assembly contains the ResponseModificationModuleProvider class that is responsible for registering the ResponseModificationModuleService service class in addition to the client ResponseModificationModule module class, as shown in Figure 5.

Figure 5 Module Provider Class

public sealed class ResponseModificationModuleProvider : 
  ConfigurationModuleProvider
{
  public override Type ServiceType
  {
    get { return typeof(ResponseModificationModuleService); }
  }

  public override ModuleDefinition 
    GetModuleDefinition(IManagementContext context)
  {
    return new ModuleDefinition(Name,
      "Mvolo.ResponseModification.UI.Client.ResponseModificationModule,"+
      "Mvolo.ResponseModificationUI.Client," +
      "Version=1.0.0.0, Culture=neutral," +
      "PublicKeyToken=309ac0e1b5482072");
  }

  protected override string ConfigurationSectionName
  {
    get { return "responseModification"; }
  }
}

The ResponseModificationModuleService class derives from the ConfigurationModuleProvider class, which provides built-in support for controlling IIS Manager feature delegation based on the delegation state of the underlying configuration section. All you have to do is supply the configuration section name, responseModification, and IIS Manager automatically toggles the delegation state of the feature based on whether the section is locked or unlocked for any particular configuration path. The Microsoft.Web.Management framework provides several other ModuleProvider base classes that support various other delegation scenarios for the IIS Manager tool.

The GetModuleDefinition method returns the type of the IIS Manager module that will be instantiated on the client in order to register the required IIS Manager UI components such as the management page itself.

Note that the type of the client-side ResponseModificationModule class is a string, not a Type object, because the server assembly may not reference the client assembly that will be loaded in IIS Manager on a remote client machine. This is one side effect of the fact that the client and server components may be running in different processes and cannot share custom types.

The ResponseModificationModuleService class is responsible for implementing the management functionality and exposing the service methods that will be invoked by the management page in IIS Manager (see Figure 6).

Figure 6 Module Service Class

public sealed class ResponseModificationModuleService : ModuleService
{
  [ModuleServiceMethod]
  public ArrayList GetFilterRules()
  {
    ArrayList items = new ArrayList();

    ResponseModificationSection section = 
      (ResponseModificationSection)ManagementUnit.Configuration
        .GetSection("responseModification",
          typeof(ResponseModificationSection));

    foreach (ResponseModificationRuleElement rule in section.Rules)
    {
      items.Add(GetPropertyBag(rule));
    }

  return items;
  }
  ...
}  

The GetFilterRules method is an example of several methods exposed by the service, which perform management tasks using the configuration system and possibly other resources that are local to the server. The service is always instantiated on the server, so it always acts on local resources and does not need to worry about accessing resources differently in the remote administration scenario. Note that I'm again using the Microsoft.Web.Administration API to access the responseModification configuration section, and am using the strongly typed ResponseModificationConfigurationSection wrapper created for the module to access the configuration.

The ManagementUnit property is the central entry point to the local server, exposing a number of other objects that allow access to the configuration system and other server-centric management objects that have been created by the Microsoft.Web.Management framework to assist with server management tasks. As a best practice, service implementations should always use the management unit for local configuration management tasks instead of creating their own configuration systems.

Methods like GetFilterRules can return information to the client by using basic types such as ArrayList to relay information to the client components. Again, you cannot communicate using strongly typed classes defined in the server or client assemblies because they are intended to be separate and should not have references to each other. ResponseModificationModuleService also defines additional service methods similar to GetFilterRules, including EditFilterRule, AddFilterRule, and DeleteFilterRule, to support the required management operations that may be requested by the Response Modification module page.

Creating the Module Page

The client components define the actual GUI management functionality provided to the user by the IIS Manager tool. The client assembly typically contains the implementation of the following classes:

  • The Microsoft.Web.Management.Client.Module class, which is responsible for registering any required IIS Manager pages and other UI extensions.
  • The Microsoft.Web.Management.Client.ModulePage class, which describes the actual management page displayed by IIS Manager.
  • The Microsoft.Web.Management.Client.ModuleServiceProxy class, which provides the client components with a local proxy class for invoking the service methods exposed by the ModuleService.

The Mvolo.ResponseModificationUI.Server.dll assembly contains the ResponseModificationModule class shown in Figure 7 (not to be confused with the actual IHttpModule class that provides the module services in the IIS request processing pipeline), which provides the main entry point for registering all of the needed UI components in IIS Manager. This class registers the ResponseModificationModulePage class, which describes the actual management page.

Figure 7 Module Class

public sealed class ResponseModificationModule : Module
{
  protected override void Initialize(IServiceProvider serviceProvider, 
    ModuleInfo moduleInfo)
  {
    base.Initialize(serviceProvider, moduleInfo);

    IControlPanel controlPanel =
      (IControlPanel)GetService(typeof(IControlPanel));

    controlPanel.RegisterPage(
      new ModulePageInfo(this,
      typeof(ResponseModificationModulePage),
      Resources.PageTitle,
      Resources.PageDescription,
      null,
      null,
      Resources.PageText
      ));
  }
}

Each Module implementation is created once per the lifetime of a management connection made with IIS Manager, and it is responsible for registering all of the necessary management pages and UI elements for the connection. ResponseModificationModule registers the ResponseModificationModulePage class, which defines the contents of the management page.

To be honest, I am not a big fan of GUI programming, and I much prefer to write low-level server code that does not require interface development. Lucky for me, the Microsoft.Web.Management framework provides a number of base classes and supporting classes for implementing common-looking management pages, including the Microsoft.Web.Management.Client.Win32.ModuleListPage class that I used for ResponseModificationModulePage.

This class provides a built-in List view for viewing and managing lists of items, including sorting the list and interacting with list items. With a minimum amount of customization, I was able to create a management page containing a list of response modification rules (see the center panel of Figure 8).

Figure 8 Response Modification Page in IIS Manager

Figure 8** Response Modification Page in IIS Manager **(Click the image for a larger view)

Next, I created the list of actions, displayed in the right panel, for allowing the response modification rules to be added, edited, and removed. I took advantage of the Microsoft.Web.Management.Client.TaskList class to create this task list (shown in the right panel in Figure 8).

With just a little more work, the Response Modification feature shown in Figure 8 was born. You can review the details of the UI in the source code for the Response Modification framework.

The initial page creation, and the add, edit, and delete operations triggered from the action panel are performed by invoking methods on the ResponseModificationModuleServiceProxy class, which provides a local proxy to the module methods exposed by the module service:

public sealed class ResponseModificationModuleServiceProxy : 
  ModuleServiceProxy
{
  public ArrayList GetFilterRules()
  {
    return (ArrayList)Invoke("GetFilterRules");
  }

  public void AddFilterRule(PropertyBag bag)
  {
    Invoke("AddFilterRule", bag);
  }

  ...
} 

IIS Manager automatically relays calls made to the module service proxy class to the associated module service over the communication channel, which may be a local shared memory channel or an https channel to a remote server.

Deploying the Extension

To deploy the IIS Manager extension, note that you have to register the module provider type in the IIS Manager configuration file on the server (%windir%\system32\inetsrv\config\administration.config). The configuration shown in Figure 9 registers the module provider and enables it to be used for all sites by default. Note that both the client and server assemblies that comprise the extension, Mvolo.ResponseModificationUI.Server.dll and Mvolo.ResponseModificationUI.Client.dll, must be registered in the Global Assembly Cache (GAC) and therefore must be strong-named and signed. This is a requirement for being able to install IIS Manager extensions.

Figure 9 IIS Manager Extension Configuration

<moduleProviders>
  ...

  <!-- Mvolo ResponseModification -->
  <add name="ResponseModification" 
    type="Mvolo.ResponseModification.UI.Server
        .ResponseModificationModuleProvider, 
      Mvolo.ResponseModificationUI.Server, 
      Version=1.0.0.0, Culture=neutral, 
      PublicKeyToken=895e90205a14f2aa, 
      processorArchitecture=MSIL" />
</moduleProviders>

<!-- For all Sites -->
<location path=".">
  <modules>
    ...
    <add name="ResponseModification" />
  </modules>
</location>

When IIS Manager is used to manage the server remotely, the tool will automatically prompt the user to download the client assembly whenever it is not present on the client already (this currently only works when managing IIS 7.0 on Windows Server 2008 from a Windows Vista SP1, Windows XP, or Windows Server 2003 client by using the remote IIS Manager available online from iis.net/ downloads/?tabid=34&g=6&i=1524). Be sure that you trust both the server you are connected to and the publisher of the IIS Manager extension before accepting this installation, as otherwise it may possibly allow untrusted code to execute on your machine with your user account privileges.

Tying It All Together

After deploying the module and installing the configuration section schema and the IIS Manager extension, the Response Modification feature is ready to use. You can now enable the feature for any of the applications on your server and configure it with any of the IIS 7.0 configuration tools and APIs.

In addition, you can use the IIS Manager tool to quickly manage the response modification rules for applications, both on the local server or on a remote server. Using the IIS Manager delegation support, you can even configure which users have the ability to remotely create and manage the response modification rules for specific sites on a server.

To demonstrate the Response Modification feature in action, Figure 10 shows how I configured rules for my Qdig image gallery application (featured in msdn.microsoft.com/msdnmag/issues/08/01/PHPandIIS7). Figure 11 shows how I use the Mvolo.ResponseModification.Filters.RegExReplace filter provided with the Response Modification framework to intelligently insert header and footer content into all pages in the Web site, without modifying the actual source code of the application.

Figure 10 Enabling Headers and Footers

<responseModification enabled="true">
  <add name="Header" 
    conditionType=
      "Mvolo.ResponseModification.Conditions.ContentTypeCondition"
    condition="text/html" 
    replaceType="Mvolo.ResponseModification.Filters.RegExReplace" 
    replace="&lt;body([^>]*)>" 
    replaceWith="&lt;body$1>&lt;h1 align='center'>
      Welcome to my gallery!&lt;/h1>" 
    options="IgnoreCase" />
  
  <add name="Footer" 
    conditionType=
      "Mvolo.ResponseModification.Conditions.ContentTypeCondition"
    condition="text/html" 
    replaceType="Mvolo.ResponseModification.Filters.RegExReplace" 
    replace="&lt;/body>" 
    replaceWith="&lt;h3 align='center'>
      Copyright mvolo 2007&lt;/h3>&lt;/body>" 
    options="IgnoreCase"  />
 </responseModification>

Figure 11 Using Response Modification to Modify Responses

Figure 11** Using Response Modification to Modify Responses **

The Response Modification module can also be used to easily implement any number of custom content insertions, hyperlink substitutions, and other response modification schemes by implementing replacement filters. These filters can then be deployed globally, or with an application, and configured via configuration rules in the responseModification configuration section.

Build Your Own

There are quite a few creative uses for the Response Modification feature whenever it is not possible to achieve the same results by modifying the source code of an application (which is always more efficient than modifying the response on the fly). For example, I also use it to inject a small script into HTML responses that changes image tags to use highly compressed versions of images and then replaces them with higher-quality versions on the fly to provide for a more responsive browsing experience for slow clients. This also uses a custom imaging handler that can provide JPEG images with any desired compression level for a static image using the Microsoft Windows Imaging Component APIs. Figure 11 shows the result in action, including the header, footer, and the low-quality preloaded image (right before it is automatically replaced with the higher resolution version).

Modifying responses on the fly can be an expensive mechanism, both in terms of CPU usage and memory requirements as multiple large buffers must be allocated to store transformed versions of the responses. This overhead may or may not be acceptable in production Web sites, depending on the types of response modification filters used, the number of them, and the performance requirements of the application.

In order to learn more about using the Response Modification framework, you should download it, along with its source code, from the Response Modification development site (www.mvolo.com/responsemod). After you understand how response filters work and can plan for using them given performance overhead considerations, look for further samples on the Response Modification development site. To learn more about extending IIS 7.0, be sure to visit iis.net and my blog (mvolo.com), which is dedicated to developing and using IIS 7.0.

Mike Volodarsky is a Technical Program Manager on the Web Platform and Tools Team at Microsoft. Over the past four years, he has driven the design and development of the core feature-set for ASP.NET 2.0 and IIS 7.0. He is now focusing on helping customers leverage the power of these technologies in Windows Server 2008.