ASP.NET Integration With IIS 7.0

Introduction

Since its release, ASP.NET has been the platform of choice for developing web applications on the Windows / IIS platform. ASP.NET 2.0 took web application development to a new level, allowing developers to build more powerful applications faster than ever before.

IIS 7.0 takes ASP.NET further by integrating the ASP.NET runtime extensibility model with the core server. This allows developers to fully extend the IIS 7.0 server with the richness of ASP.NET 2.0 and the .NET Framework, instead of using the lower level IIS C++ APIs. Existing ASP.NET applications also immediately benefit from tighter integration using existing ASP.NET features like Forms Authentication, Roles, and Output Caching for all content.

While IIS 7.0 provides the improved ASP.NET integration by default, there is a choice: IIS 7.0 supports both the new and the old ASP.NET integration modes that can be used side by side on the same server.

This article discusses the improvements introduced by the new ASP.NET integration mode, the architecture of the two modes, and describes how to select and configure the integration modes for ASP.NET applications.

ASP.NET Enhancements on IIS 7.0

Better ASP.NET integration in IIS 7.0 both enhances existing applications, and allows new applications to take advantage of ASP.NET features in new ways:

  • ASP.NET services can be used for all content types. In the past, ASP.NET functionality such as Forms Authentication, Roles, URL Authorization, and Output Caching were only available to ASP.NET content types (ASPX pages, for example). Static files, ASP pages, and other content types could not benefit from these services.

In IIS 7.0, all ASP.NET services are provided uniformly to all content. For example, you can protect all of your web content, including images and ASP pages with your existing ASP.NET 2.0 access control solution built on ASP.NET Forms Authentication, Membership and Login controls.

  • Fully extend IIS with ASP.NET. Previous versions of IIS frequently required server extensibility to be developed using the native ISAPI filter or extension extensibility mode, due to the runtime limitations of ASP.NET.

IIS 7.0 allows ASP.NET modules to plug in directly into the server pipeline, with the same runtime fidelity as modules developed with the native (C++) server API. ASP.NET modules can execute in all runtime stages of the request processing pipeline, and be executed in any order with respect to native modules. The ASP.NET API is also expanded to allow more control over request processing then was previously possible.

  • Unified server runtime. Tighter ASP.NET integration also allows many of the features between IIS 7.0 and ASP.NET to be unified.

IIS 7.0 features unified configuration for IIS and ASP.NET modules and handlers. Many other features, including custom errors, and tracing, have been unified to allow better management and cohesive application design.

ASP.NET Integration Architecture

In IIS 6.0 and previous releases, ASP.NET was implemented as an IIS ISAPI extension.

A request to an ASP.NET content type would be first processed by IIS, and then forwarded to the ASP.NET ISAPI DLL, which hosted the ASP.NET request pipeline and page framework. Requests to non-ASP.NET content, such as ASP pages, or static files, would be processed by IIS or other ISAPI extensions and were not visible to ASP.NET.

The major limitation of this model is the fact that services provided by ASP.NET modules, and custom ASP.NET application code, was not available to non-ASP.NET requests. In addition, ASP.NET modules were unable to affect certain parts of IIS request processing that occurred before and after the ASP.NET execution path.

 

Figure 1: IIS 6.0 & ASP.NET Pipelines

In IIS 7.0, the ASP.NET request processing pipeline overlays the IIS pipeline directly, essentially providing a wrapper over it instead of plugging into it.

A request arriving for any content type is processed by IIS 7.0, with both native IIS modules and ASP.NET modules able to provide request processing in all stages. This enables services provided by ASP.NET modules like Forms Authentication or Output Cache to be used for requests to ASP pages, PHP pages, static files, and so on.

The ability to plug in directly into the server pipeline allows ASP.NET modules to replace, run before, or run after any IIS 7.0 functionality. This enables, for example, a custom ASP.NET basic authentication module written to use the Membership service and SQL Server user database to replace the built in IIS basic authentication feature that works only with Windows accounts.

In addition, the expanded ASP.NET APIs take advantage of direct integration to enable more request processing tasks. For example, ASP.NET modules can modify request headers before other components process the request, inserting an Accept-Language header before ASP applications execute in order to force localized content to be sent back to the client based on user preference.

 

Figure 2: IIS 7.0's Integrated Mode

Because of the runtime integration, IIS 7.0 and ASP.NET can use the same configuration for enabling and ordering server modules, and configuring handler mappings. Other unified functionality includes tracing, custom errors, and output caching.

Compatibility

Most notably, the integrated architecture maintains the existing ASP.NET runtime architecture and APIs, allowing existing ASP.NET applications and services to work out of the box. With just a few modifications, they can be changed to take advantage of the new ASP.NET capabilities.

Likewise, developers can continue to write new applications to familiar ASP.NET APIs while harnessing the benefits of the runtime integration.

IIS 7.0 continues to provide the "Classic" ASP.NET mode for ASP.NET applications that have specific compatibility requirements not met by the Integrated mode. Administrators can select the desired integration mode per application pool, which enables applications using both the new and the Classic ASP.NET modes to function side by side on the same server.

Migrating ASP.NET Applications to IIS 7.0 Integrated mode

On IIS 7.0, ASP.NET is configured to operate in the new Integrated mode by default. This enables your application to take advantage of Integrated mode enhancements with minimal modifications.

Because of the configuration unification, some applications may require migration in order to operate property in Integrated mode. By default, the server provides assistance with migration. It detects applications that require migration, and returns an error message requesting the application be migrated.

The following configuration causes the migration error:

  1. The application web.config file defines <httpModules> configuration.
    The application loads new ASP.NET modules, or removes existing ones.
    In Integrated mode, ASP.NET modules are specified together with native modules in the unified <system.webServer>/<modules> configuration section.
    The ASP.NET modules specified in the <system.web>/<httpModules> configuration section must be moved to the new configuration section in order to take effect. Subsequently, new ASP.NET modules must be added directly to the unified <modules> section.
  2. The application web.config file defines <httpHandlers> configuration.
    The application uses custom handler mappings for some content types.
    In Integrated mode, the ASP.NET handler mappings must be specified in the unified <system.webServer>/<handlers> configuration section in order to take effect. Subsequently, new ASP.NET handler mappings must be added directly to the unified <handlers> section.
    The section replaces both the ASP.NET <httpHandlers> configuration AND the IIS 7.0 scriptmaps configuration, both of which previously had to be configured in order to set up an ASP.NET handler mapping.
  3. The application web.config file defines <identity impersonate="true" /> configuration.
    The application impersonates client credentials (most common with intranet applications). In Integrated mode, client impersonation is not available in some early request processing stages. In the majority of cases, this is not a problem and you can turn off the error – otherwise, you must configure this application to run using the Classic ASP.NET mode.

When this error is generated, it can generally either migrate the application configuration (recommended in cases 1 and 2, above), or move the application to use Classic ASP.NET mode (in case 3).

Migrating the Application Configuration

IIS 7.0 takes care of migrating the application by using the APPCMD.EXE command line tool to perform the migration. The migration error message contains the command that is executed in command line window (which you must run--right click the Programs\Accessories\Command Prompt icon, and choose "Run as administrator") in order to instantly migrate your application to Integrated mode.

The basic format of the migration command is the following:

%windir%\system32\inetsrv\APPCMD.EXE migrate config <Application Path>

Where <Application Path> is the virtual path of the application containing the site name, such as "Default Web Site/app1".

When migration is complete, your application runs in both Integrated and Classic modes without a problem.

Note: If you change the configuration after migration, the server will not prompt you to migrate again. After initial migration, you must make sure that your configuration remains in sync between the two modes – manually migrate the application again using the APPCMD.EXE command line tool.

Moving Back to Classic ASP.NET integration Mode

If you would rather return to the Classic ASP.NET mode, move your application to an application pool configured to run in Classic mode. Other applications continue running in the new Integrated mode side by side with the Classic mode application.

See Changing ASP.NET modes for an application for more information on moving an application to the Classic ASP.NET mode.

Disabling the Migration Error Message

If you have manually migrated your configuration, or want to remain in Integrated mode without migrating your configuration (not recommended), disable the migration error message by adding the following to the application's web.config file:

<system.webServer>
<validation validateIntegratedModeConfiguration="false" />    
</system.webServer>

Note: The server automatically disables the error message after migrating the configuration with the APPCMD.EXE command line tool.

If you manually disable the migration error message, you must make sure that your application works properly in Integrated mode, as the server will no longer provide any warning regarding unsupported configuration mentioned earlier.

Changing ASP.NET Modes for an Application

If your application does not work properly in Integrated ASP.NET mode, move it to the Classic ASP.NET mode simply by moving it to another application pool.Each application pool is individually configured to use the desired ASP.NET integration mode. This allows you to run groups of applications using different ASP.NET integration modes side by side on the same server.

In order to change the ASP.NET integration mode for an application, do the following:

  1. Find or create an application pool that is configured to use the desired mode.
    By default, all new application pools on the system run in Integrated mode.
    ASP.NET setup does provide an application pool named "Classic .NET AppPool" that runs in the classic ASP.NET integration mode. You can use this application pool for applications that should not run in Integrated mode.
    You can also change the ASP.NET mode of the existing application pool either: using the IIS 7.0 Administration Tool, and the APPCMD.EXE command line tool; or, manually editing application pool configuration.
  2. Set the application to use that application pool.
    Each application is configured to use a particular application pool. By default, all applications use the default application pool named "DefaultAppPool", which runs in Integrated mode.
    You can change the application pool of an application either: using the IIS 7.0 Administration Tool, and the APPCMD.EXE command line tool; or, manually editing the application configuration.

Selecting ASP.NET Version for an Application

Historically, IIS has supported multiple versions of ASP.NET / CLR side by side-- for example, it enables the same server to run ASP.NET applications using .NET Framework v1.1 and v2.0. This support was provided by mapping a corresponding version of ASPNET_isapi.dll to serve requests for the ASP.NET content using the IIS 7.0 scriptmaps configuration.

For example, you could have the following script map configuration to enable side by side:

  1. ASP.NET v1.1 application on /app1:
    *.aspx -> d:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll
  2. ASP.NET v2.0 application on /app2:
    *.aspx -> d:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll

When a *.aspx request arrives to the application, IIS 7.0 loads the specified aspnet_isapi.dll, which loads the correct CLR version into the worker process, and process the request.

ASP.NET also provided the following ways to configure side by side scriptmaps:

  1. ASP.NET MMC extension. A user picks the version of ASP.NET to use, and the extension automatically configures the scriptmaps for the application to point to the right version of aspnet_isapi.dll.
  2. ASP.NET aspnet_regiis.exe. A user utilizes the –i, and –r options to install the scriptmaps pointing to the corresponding ASP.NET version.

Unfortunately, due to the limitation of the ability to load only one CLR version into a single worker process, the user must be careful to make sure that two applications using different versions are never configured to exist within the same application pool. With this common mistake, the first request would load the CLR of the corresponding aspnet_isapi.dll, and subsequent requests to the other version within the same application pool would fail.

IIS 7.0 recognizes that the application pool is the unit of ASP.NET versioning. As such, the version of the CLR / ASP.NET loaded in that application pool is explicitly configured in the application pool configuration. By default, IIS 7.0 pre-loads the CLR specified by this setting when loading the worker process (unless the version is configured to be empty).

Because application pools are the .NET Framework versioning boundary, the following are the options for changing the version of an ASP.NET application:

  1. Move the application to an application pool using the desired ASP.NET version.
    By default, applications use the default application pool named "DefaultAppPool", which runs ASP.NET v2.1 in Integrated mode. Move the application to the "Classic .NET AppPool" in order to run in ASP.NET v2.1 Classic mode, or another application pool of your choice.
  2. Configure the application pool within which the application is running to use the desired ASP.NET version.
    By default, all new application pools will be configured to run ASP.NET v2.1 in Integrated mode.

Note: Do not use aspnet_regiis /i or /r options to configure the version of ASP.NET for a particular application, or globally.

IIS 7.0 uses pre-conditioned handler mappings in order to automatically select the right set of handler mappings (to ASPNET_isapi.dll in Classic mode or managed handler types directly in Integrated mode) depending on the configured CLR version and managed integration mode of the application pool. The ASP.NET 2.0 setup installs these handler mappings at the server level.

Taking Advantage of Integrated ASP.NET Mode

On IIS 7.0, ASP.NET applications run in Integrated mode by default. However, in order to take advantage of the benefits provided by tighter integration, you must make some modification to application configuration. Further, you can develop new ASP.NET components that take advantage of the Integrated mode to provide powerful functionality to your application.

Enabling ASP.NET Services for All Types of Content

In Integrated mode, services provided by ASP.NET modules are available to requests for all content types. However, by default, ASP.NET modules are configured to execute only for requests to ASP.NET content for backward compatibility.

To do this, attach a managedHandler precondition to each ASP.NET module in the configuration section at the server level:

<modules>
     <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"
             preCondition="managedHandler" />
     <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule"
             preCondition="managedHandler" />
    ...
</modules>

The precondition is a rule that the server evaluates on every request to determine whether a module will be executed. The managedHandler precondition is only true for requests to content types mapped to ASP.NET handlers.

To apply functionality provided by an ASP.NET module to all requests, remove the module entry, and re-add it without the precondition in the application's root web.config. For example, to enable ASP.NET Forms-based authentication for the entire application, do the following:

<modules>
    <remove name="FormsAuthentication" />
     <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
    …
</modules>

With this change, the FormsAuthentication module executes for all requests in your application. This allows you to protect all of the application content with Forms-based authentication. For more information on leveraging the Integrated mode to provide Forms-based authentication for all application content, see Taking Advantage of Integrated Pipeline Mode walkthrough.

You can also use a shortcut to enable all managed (ASP.NET) modules to run for all requests in your application, regardless of the "managedHandler" precondition. To enable all managed modules to run for all requests without configuring each module entry to remove the "managedHandler" precondition, use the runAllManagedModulesForAllRequests property in the <modules> section:

<modules runAllManagedModulesForAllRequests="true" /> 

When you use this, the "managedHandler" precondition has no effect and all managed modules run for all requests.

Experiment with enabling other ASP.NET modules to apply to your entire application. For example, use the ASP.NET Output Cache module to output cache ASP pages, or use URL Authorization and Role Manager to configure access control rules for your photos. Or, develop your own module to bring the power of ASP.NET to your entire web site.

Building More Powerful ASP.NET Services

In Integrated mode, ASP.NET modules apply their services to all content. In addition, because ASP.NET modules execute in the unified request processing pipeline in Integrated mode, they subscribe to the same request processing stages and perform the same tasks as native server modules. At the same time, ASP.NET APIs remain largely the same, with a few key additions that unlock previously unavailable functionality.

Runtime Fidelity

In Integrated mode, the ASP.NET request processing stages exposed to modules are directly connected to the corresponding stages of the IIS 7.0 pipeline. The complete pipeline contains the following stages, exposed as HttpApplication events in ASP.NET:

  1. BeginRequest. The request processing starts.
  2. AuthenticateRequest. The request is authenticated. IIS 7.0 and ASP.NET authentication modules subscribe to this stage to perform authentication.
  3. PostAuthenticateRequest
  4. AuthorizeRequest. The request is authorized. IIS 7.0 and ASP.NET authorization modules check whether the authenticated user has access to the resource requested.
  5. PostAuthorizeRequest
  6. ResolveRequestCache. Cache modules check whether the response to this request exists in the cache, and return it instead of proceeding with the rest of the execution path. Both ASP.NET Output Cache and the new IIS 7.0 Output Cache features execute here.
  7. PostResolveRequestCache
  8. MapRequestHandler. This stage is internal in ASP.NET, and is used to determine the request handler.
  9. PostMapRequestHandler
  10. AcquireRequestState. The state necessary for the request execution is fetched. ASP.NET Session State, and Profile modules obtain their data here.
  11. PostAcquireRequestState
  12. PreExecuteRequestHandler. Any tasks before the execution of the handler are performed here.
  13. ExecuteRequestHandler. The request handler executes here. ASPX pages, ASP pages, CGI programs, and static files are served here.
  14. PostExecuteRequestHandler
  15. ReleaseRequestState. The request state changes are saved, and the state is cleaned up here. ASP.NET Session State and Profile modules use this stage for cleanup.
  16. PostReleaseRequestState
  17. UpdateRequestCache. The response can be stored in the cache for future use here. The ASP.NET Output Cache and IIS 7.0 Output Cache modules execute here to save the response to their caches.
  18. PostUpdateRequestCache
  19. LogRequest. This stage logs the results of the request, and is guaranteed to execute even if errors occur.
  20. PostLogRequest
  21. EndRequest. This stage performs any final request cleanup, and is guaranteed to execute even if errors occur.
Using the familiar ASP.NET APIs, the ability to execute in the same stages as IIS 7.0 modules makes tasks that were only previously accessible in native ISAPI filters and extensions now possible in managed code.

 For example, you can now write modules that do the following:

  1. Intercept the request before any processing has taken place, for example for re-writing URLs or performing security filtering.
  2. Replace built in authentication modes.
  3. Modify the incoming request contents, such as request headers.
  4. Filter outgoing responses for all content types.

 See Developing an IIS 7.0 Module with .NET for a good example of extending IIS 7.0 with a custom ASP.NET authentication module.

Expanded ASP.NET APIs

The ASP.NET APIs remain backward compatible with previous releases, which allows existing modules to work in IIS 7.0 without modification, and to apply to all application content without code changes.

However, modules written for IIS 7.0 Integrated mode can take advantage of a few additional APIs to enable key request processing scenarios not previously available.

The new HttpResponse.Headers collection allows modules to inspect, and manipulate, response headers that other application components generate. For example, you can change the Content-Type header generated by an ASP page to prompt a download dialog box in the browser. The Cookies collection on the HttpResponse class is also enhanced to allow modification of cookies generated as part of the request processing, even if they were created outside of ASP.NET.

The HttpRequest.Headers collection available is write-enabled, allowing modules to manipulate the incoming request headers. Use this to change the behavior of other server components – for example, force a localized application to respond to the client in a different language by dynamically changing the value of the Accept-Language header.

Finally, the HttpRequest.ServerVariables collection is now writeable, allowing IIS 7.0 server variables to be set. ASP.NET modules use this functionality to change IIS 7.0 provided values, and create new server variables visible to other application frameworks, like PHP.

Runtime Integration

In addition to the new APIs, the Integrated mode enables existing ASP.NET functionality to provide more value to your application.

The tracing facilities provided by ASP.NET, including the System.Diagnostics.Trace class, and the ASP.NET page tracing feature, now emit trace information into the IIS 7.0 trace system. This enables the trace information generated during request processing by both IIS 7.0 and ASP.NET components to be placed in a single log file, facilitating better diagnostics of server issues.

The ASP.NET response filtering feature, which allows responses to be changed via a Stream interface before it goes to the client, is enhanced to allow filtering of non ASP.NET content. Therefore, you can use ASP.NET filtering on all server content, or selectively install the filter only for requests to content you want to process. With this capability, you can write filtering features that inject or censor certain content in the site's responses, regardless of whether this content comes from an ASPX page or a static file.

Summary

ASP.NET Integration in IIS 7.0 unlocks the full potential of ASP.NET, enabling developers to create powerful server components with the ease and richness of ASP.NET and the .NET Framework. To learn more about leveraging ASP.NET Integrated mode for existing applications, see Taking Advantage of the Integrated Pipeline Mode. For information on building new ASP.NET components to extend the server, see Developing an IIS 7.0 Module with .NET.

posted @ 2010-01-29 16:53  架构师聊技术  阅读(363)  评论(0编辑  收藏  举报