From Browser to ASP.NET
Let's start at the beginning of the lifetime of a typical ASP.NET Web Request. A request starts on the browser where the user types in a URL, clicks on a hyperlink or submits an HTML form (a POST
request). Or a client application might make call against an ASP.NET-based Web service, which is also serviced by ASP.NET. On the server side, the Web server (Internet Information Server 5 or 6) picks up the request. At the lowest level ASP.NET interfaces with IIS through an ISAPI extension. With ASP.NET this request usually is routed to a page with an .aspx
extension, but how the process works depends entirely on the implementation of the HTTP handler that is set up to handle the specified extension. In IIS the extension .aspx
is mapped through an "Application Extension" (aka. a script map) mapped to the ASP.NET ISAPI dllaspnet_isapi.dll
. Every request that fires ASP.NET must go through an extension that is registered and points at aspnet_isapi.dll
|ISAPI is the first and highest performance entry point into IIS for custom Web request handling.|
Depending on the extension, ASP.NET routes the request to an appropriate handler that is responsible for picking up requests. For example, the .asmx
extension for Web services routes requests not to a page on disk but a specially attributed class that identifies it as a Web service implementation. Many other handlers are installed with ASP.NET and you can also define your own. All of these
HttpHandlers are mapped to point at the ASP.NET ISAPI extension in IIS, and configured in web.config to get routed to a specific HTTP handler implementation. Each handler is a .NET class that handles a specific extension ranging from simple Hello World behavior with a couple of lines of code, to very complex handlers like the ASP.NET page or Web service implementations. For now, just understand that an extension is the basic mapping mechanism that ASP.NET uses to receive a request from ISAPI and then route it to a specific handler that processes the request.
The ISAPI Connection
ISAPI is a low level unmanaged Win32 API. The interfaces defined by the ISAPI spec are very simplistic and optimized for performance. They deal with raw pointers and function pointer tables for callbacksbut they provide the lowest and most performance-oriented interface that developers and tool vendors can use to hook into IIS. Because ISAPI is very low level it's not
well suited for building application-level code, and ISAPI tends to be used primarily as a bridge interface to provide application server-type functionality to higher level tools. For example, ASP and ASP.NET both are layered on top of ISAPI as is Cold Fusion, most Perl, PHP and JSP implementations running on IIS as well as many third party-solutions. ISAPI is an excellent tool to provide the high performance plumbing interface to higher level applications, which can then abstract the information that ISAPI provides. In ASP and ASP.NET, the engines abstract the information provided by the ISAPI interface in the form of objects like Request and Response that read their content out of the ISAPI request information. Think of ISAPI as the plumbing. For ASP.NET the ISAPI DLL is very lean and acts merely as a routing mechanism to pipe the inbound request into the ASP.NET runtime. All the heavy lifting and processingeven the request thread managementhappens inside of the ASP.NET engine and your code.
The ISAPI protocol supports both ISAPI extensions and ISAPI filters. Extensions are a request handling interface and provide the logic to handle input and output with the Web serveressentially a transaction interface. ASP and ASP.NET are implemented as ISAPI extensions. ISAPI filters are hook interfaces that allow the ability to look at every
request that comes into IIS and to modify the content or change the behavior of functionalities like authentication (see Sidebar 1
). Incidentally, ASP.NET maps ISAPI-like functionality via two concepts: HTTP handlers (extensions) and HTTP modules (filters). I'll show you these in more detail later.
ISAPI is the initial code point that marks the beginning of an ASP.NET request. ASP.NET maps various extensions to its ISAPI extension that lives in the .NET Framework directory:
|Figure 1: IIS Extension Mapping: IIS maps various extensions such as .ASPX to the ASP.NET ISAPI extension. This mechanism routes requests into ASP.NET's processing pipeline at the Web server level.|
You can interactively see these mappings in the IIS Service manager as shown in Figure 1
. Look at the root of the Web Site and the Home Directory tab, then Configuration | Mappings.
You shouldn't set these extensions manually because .NET requires a number of them. Instead, use the aspnet_regiis.exe
utility to make sure that all the various scriptmaps get registered properly:
cd <.NetFrameworkDirectory> aspnet_regiis - i
This will register the version of the ASP.NET runtime for the entire Web site by registering the scriptmaps and setting up the client-side scripting libraries used by the various controls for uplevel browsers. Note that it registers the specific version of the CLR installed in the above directory. Options on aspnet_regiis
let you configure virtual directories individually. Each version of the .NET Framework has its own version of aspnet_regiis
and you need to run the appropriate one to register a site or virtual directory for a specific version of the .NET Framework. Starting with ASP.NET 2.0, an IIS ASP.NET configuration page lets you pick the .NET version interactively in the IIS management console.
IIS 5 and 6 Work Differently
|Figure 2: Request Flow: The figure shows the request flow from IIS to the ASP.NET runtime and through the request-processing pipeline from a high level. IIS 5 and IIS 6 interface with ASP.NET in different ways but after reaching the ASP.NET pipeline, the flow is identical.|
When a request comes in, IIS checks for the script map and routes the request to the aspnet_isapi.dll
. The operation of the DLL and how it gets to the ASP.NET runtime varies significantly between IIS 5 and 6. Figure 2
shows a rough overview of the flow.
IIS 5 hosts aspnet_isapi.dll
directly in the inetinfo.exe
process (or one of its isolated worker processes if you have isolation set to medium or high for the Web or virtual directory). When the first ASP.NET request comes in, the DLL spawns a new process in another EXEaspnet_wp.exe
and routes processing to this spawned process. This process in turn loads and hosts the .NET runtime. Every request that comes into the ISAPI DLL then routes to this worker process via Named Pipe calls.
IIS 6Viva the Application Pool
IIS 6 changes the processing model significantly in that IIS no longer hosts any foreign executable code such as ISAPI extensions directly. Instead, IIS 6 always creates a separate worker processan application pool
and all processing occurs inside of this process, including execution of the ISAPI DLL. Application pools are a big improvement for IIS 6, as they allow very granular control over what executes in a given process. You can configure application pools for every virtual directory or the entire Web site, so you can isolate every Web application easily into its own process that will be completely isolated from any other Web application running on the same machine. If one process dies it will not affect any others, at least from the Web processing perspective.
In addition, application pools are highly configurable. You can configure each pool's execution security environment individually by setting an execution impersonation level for the pool that allows you to customize the rights given to a Web application in that same granular fashion. One big improvement for ASP.NET is that the application pool replaces most of the ProcessModel entry in machine.config
. This entry was difficult to manage in IIS 5, because the settings were global and could not be overridden in an application-specific web.config
file. When running IIS 6, the ProcessModel setting is mostly ignored and settings are instead read from the application pool. I say mostlysome settings, such as the size of the ThreadPool and IO threads still are configured through this key because they have no equivalent in the application pool settings of the server.
|IIS6, unlike previous servers, is fully optimized for ASP.NET|
Because application pools are external executables they can also be easily monitored and managed. IIS 6 provides a number of health checking, restarting and timeout options that can detect and in many cases correct problems with an application. Finally IIS 6's application pools don't rely on COM+ as IIS 5 isolation processes did. That has improved performance and stability, especially for applications that need to use COM objects internally.
Although IIS 6 application pools are separate executables (EXEs), they are highly optimized for HTTP operations because they communicate directly via a kernel mode HTTP.SYS driver. Incoming requests are routed directly to the appropriate application pool. InetInfo acts merely as an administration and configuration servicemost interaction occurs directly between HTTP.SYS and the application pools, all of which translates into a more stable and higher performance environment than was available with IIS 5. This is especially true for static content and ASP.NET applications.
An IIS 6 application pool also has intrinsic knowledge of ASP.NET. At the same time, ASP.NET can communicate using new low level APIs, providing direct access to the HTTP cache APIs that can offload caching from the ASP.NET level directly into the Web server's cache.
In IIS 6, ISAPI extensions run in the application pool worker process. The .NET runtime also runs in this same process, so communication between the ISAPI extension and the .NET runtime happens in-process, which is inherently more efficient than the named pipe interface that IIS 5 must use. Although the IIS hosting models are very different, the actual interfaces into managed code are very similaronly the process in getting the request routed varies a bit.