ASP.NET Internals: Request Architecture(http://www.codeproject.com/KB/aspnet/aspnetrequestarchitecture.aspx)

Introduction

Most developers are familiar with the high level abstractions that ASP.NET provides for them such as Web Forms and Web Services. However, underneath these abstractions sits a very interesting and advanced architecture. Knowing the under works of this architecture not only elevates the ASP.NET developer into the advanced zone but also helps him/her write a better designed applications and solve advanced problems that occur way below the high level ASP.NET use.

This article inspects how ASP.NET (and IIS) handles requests. On the way I will discuss in detail what happens inside the ASP.NET architecture from the moment a request leaves the browser until it goes all the way through the ASP.NET runtime.

Info: After the request finishes the ASP.NET runtime, the ASP.NET page model starts executing. This is beyond the scope of this article, but it will be the topic of my next article.

The process begins once a user requests an ASP.NET resource via the browser. For example let us say that a user requested the following URL: http://www.myserver.com/myapplication/mypage.aspx. The request will reach “myserver” which has Windows Server 2003 and IIS 6.0 installed.

Kernel Mode http.sys driver picks up the request

Once the request reaches IIS, it is detected by the http.sys kernel mode driver. Before going further let us examine what is the http.sys kernel mode driver and what is that it does.

Generally speaking, Windows provides two modes: User Mode and Kernel Mode. User applications run in User Mode and operating system code run in Kernel Mode. If a user application needs to work directly with the hardware; that specific action is done by a Kernel Mode process. The obvious purpose of these modes is to protect the operating system components from being damaged by user applications. So now that we know what User Mode and Kernel Mode are, what is the role of the http.sys kernel mode driver?

When you create a new IIS Web Site, IIS registers the site with http.sys, which then receives any HTTP requests for any web application within the site. The http.sys functions as a forwarder, directing the http requests to the User Mode process that runs the web application. In this case the User Mode process is the worker process running the application pool which the web application runs under. The http.sys implements a queuing mechanism by creating as many queues as there are application pools in IIS.

Following up with our example, once the request reaches “myserver”, http.sys picks up the request. Let us say that “myapplication” is configured to run under application pool “myapplicationpool”; in this case http.sys inspects the request queue of “myapplicationpool” and forwards the request to worker process under which “myapplicationpool” is running under.

Ok so now the request is forwarded to the application pool as explained in the previous section. Each application pool is managed by an instance of the worker process “w3wp.exe”. The “w3wp.exe” runs by default under the “NetworkService” account. This can be changed as follows: Right click on the application pool hosting your application--Properties--Identity Tab. Recall that the application pool is running by the worker – the “w3wp.exe”. So now the worker process takes over.

The worker process loads the ASP.NET ISAPI

The worker process “w3wp.exe” looks up the URL of the request in order to load the correct ISAPI extension. The requested resource in the URL is “mypage.aspx”. So what happens next? A full discussion of ISAPI extensions (and filters) is beyond the scope of this article but in short ISAPI extensions are IIS way to handle requests for different resources. Once ASP.NET is installed it installs its own ISAPI extension (aspnet_isapi.dll) and adds the mapping into IIS. IIS maps various extensions to its ISAPI extension. You can see the mappings in the IIS as follows: Right click on the Web Site-Properties-Home Directory Tab-Configuration Button-Mappings Tab. The figure below shows the mappings.

mappings.jpg

As you can see the “.aspx” extension is mapped to the aspnet_isapi.dll extension. So now the worker process passes the request to the aspnet_isapi extension. The aspnet_isapi extension in turn loads the HTTP Runtime and processing of the request starts.

Before inspecting what happens inside the HTTP Runtime let us examine some details about how the worker process loads the web application. The worker process loads the web application assembly, allocating one application domain for the application. When the worker process starts a web application (in its application domain), the web application inherits the identity of the process (NetworkService by default) if impersonation is disabled. However, if impersonation is enabled, each web application runs under the account that is authenticated by IIS or the user account that is configured in the web.config.

  • Identity impersonate=”true”
    • If only anonymous access is enabled by IIS, the identity that is passed to the web application will be [machine]\IUSR_[machine]
    • If only integrated Windows authentication is enabled in IIS, the identity that is passed to the web application will be the authenticated windows user.
    • If both integrated windows authentication and anonymous access are enabled, the identity that is passed to the web application will depend on the one that was authenticated by IIS. IIS first attempts to use anonymous access to grant a user access to a web application resource. If this attempt fails, it then tries to use windows authentication
  • Identity impersonate=”true” username=”username” password=”password” This allows the web application to run under specific identity

 

 

<>A request is issued via the browser

 

The request is forwarded to the application pool

Info: There are differences between IIS 6.0 and IIS 5.0 in the way they handle requests. First, the http.sys kernel mode is implemented only in IIS 6.0. It is not a feature of IIS 5.0. In IIS 5.0 the request is caught directly by the aspnet_asapi module which in turn passes the request to the worker process. The worker process and the ISAPI module communicate through pipes which cause calling overhead. Moreover a single instance of the worker process serves all web applications; no application pools exist. As such the model supplied by IIS 6.0 is much improved over the IIS 5.0 model. Second, the worker process in IIS 5.0 is “aspnet_wp.exe” as opposed to “w3wp.exe” in IIS 6.0. The worker process “aspnet_wp.exe” runs under the default account “ASPNET” as opposed to “NetworkService” in IIS 6.0. You can change this account by locating the element in the “machine.config” file.
Info: IIS 7.0 presents two ways to handle ASP.NET requests. First there is the classic way which behaves the same as IIS 6.0; this is useful in compatibility scenarios. Second there is the new integrated way where ASP.NET and IIS are part of the same request processing pipeline. In this second way the .NET modules and handlers plug directly into the generic request-processing pipeline, which is much more efficient than the IIS 6.0 way.

Into the HTTP Runtime

So let us summarize what happened so far: The request has passed from the browser to http.sys which in turn passed the request to the application pool. The worker process which is running the application pool investigates the URL of the request and uses the IIS application extension mapping to load up the ASP.NET ISAPI “aspnet_isapi.dll”. The ASP.NET ISAPI will now load the HTTP Runtime, which is also called the ASP.NET Runtime.

Ok so now we begin investigating what happens inside the HTTP Runtime. The entry point of the runtime is the HttpRuntime class. The HttpRuntime.ProcessRequest method signals the start of the processing. In the following subsections we will examine what happens inside the runtime after the ProcessRequest method is called:

A new HttpContext instance of the request is created

The HttpContext lives during the lifetime of the request and is accessible via the static HttpContext.Current property. The HttpContext object represents the context of the currently active request as it contains references to objects you can access during the request lifetime such as Request, Response, Application, Server, and Cache. At any time during request processing HttpContext.Current gives you access to all of these objects. Moreover the HttpContext object contains an Items collection which you can use to store request specific information.

HttpRuntime consults HttpApplicationFactory class to load a HttpApplication object

The HttpApplicationFactory class creates a pool of HttpApplication objects for your ASP.NET application and associates each request with a HttpApplication object from that pool. If no objects exist in the pool at the time of request then the HttpApplicationFactory creates an object and passes it to the request. The net result is that by now you have your request directed to your application – running inside its App Domain space – and you have an HttpApplication object assigned for your request. So now that you know what is happening, you might be wondering what the purpose of the HttpApplication object is. HttpApplication is the outer container for your specific web application and it maps to the class defined in Global.asax. If you examine your Global.asax file you will notice that it inherits from the System.Web.HttpApplication class. There is a set of predefined events that fire during request lifetime; you can see these events in the Global.asax file. HttpApplication acts as the event controller of these events. Moreover HttpApplication maintains a list of configured HttpModules which are loaded dynamically during request processing. So where do these events and HttpModules executed? And what are exactly HttpModules and HttpHandlers? The answers of these questions are found inside the Http Pipeline.

Inside the Http Pipeline

The Http Pipeline is just as the name implies: A pipeline for the request to pass by. It is called a pipeline because it contains a set of HttpModules that intercept the request on its way to the HttpHandler. HTTP modules are classes that have access to the incoming request. These modules can inspect the incoming request and make decisions that affect the internal flow of the request. After passing through the specified HTTP modules, the request reaches an HTTP handler, whose job it is to generate the output that will be sent back to the requesting browser.

Request passes through Http Modules

HttpModules are configured on both machine level (machine.config) and application level (web.config). There are many built in HttpModules in ASP.NET that access the request and perform various functions. Of these HttpModules are Authentication, State Management, and Caching modules. ASP.NET 2.0 adds more modules such as Membership, Role Management, and Personalization. The below figure is taken from the “machine.config” file and it shows how built in modules are defined:
modules.jpg
Developers can of course write their own modules and plug them in the “machine.config” if they intend to apply the modules on all their applications or in the “web.config” of a certain application if they intend to apply the modules on that specific application. Requests inside the Http Pipeline will pass through all modules defined in the “machine.config” and web.config”. As mentioned in the previous section, these modules are maintained inside the HttpApplication and are loaded dynamically at runtime.

Request hits the Http Handler

HTTP handlers are the endpoints in the HTTP pipeline. The job of the HTTP handler is to generate the output for the requested resource. For aspx pages, this means rendering these pages into HTML and returning this HTML. Http Handlers can be configured at both machine level (machine.config) and application level (web.config). The below figure is taken from the “machine.config” and it shows how Http Handlers are set.
handlers.jpg
As you can see by the above figure, different resources are configured to use different handlers. For ASP.NET aspx pages note that it is configured to use the “PageHandlerFactory”. The job of the “PageHandlerFactory” is to provide an instance of an Http Handler that can handle the request. What the “PageHandleFactory” does is that it tries to find a compiled class that represents the requested page “mypage.aspx”. If it succeeds then it passes this compiled class as the Http Handler. If there is no compiled class to represent the requested page because the request is the first one or because the page has been modified since the last request, then the “PageHandlerFactory” compiles the requested page “mypage.aspx” and returns the compiled class. Any subsequent requests will be served by the same compiled class until the page is modified.

By now you might be wondering how come the “PageHandlerFactory” returns an instance of the compiled class to act as the handler for the request. Is the compiled class an actual Http Handler? The answer will be obvious once you inspect the code behind of your page “mypage.aspx.cs”. You will quickly notice that the page inherits from the “System.Web.UI.Page” class; this class in turn implements the “IHttpHandler” interface which makes it suitable as an Http Handler.

Info: Page compilation is beyond the scope of this article but it will be discussed along with my next article which discusses the ASP.NET page model.
Page Executing Starts

Finally the request has been handed to the appropriate Http Handler as we saw in the previous section. Next the runtime calls the IHttpHandler.ProcessRequest method and the ASP.NET Page life cycle starts. What happens next is outside the scope of this document and will be explained thoroughly in the next article.

Summary

This article discussed the hidden details of what happens whenever we request an ASP.NET page via the browser. To quickly summarize the process:

  • Request for “mypage.aspx” of web application “myapplication” is issued from the browser
  • Request reaches IIS and is picked up by the http.sys driver
  • The http.sys driver forwards the request to the application pool which “myapplication” is configured to run under
  • The worker process of the application pool “w3wp.exe” loads the ASP.NET ISAPI “aspnet_isapi.dll” by inspecting the URL and mapping extension “.aspx” to the “aspnet_isapi”. These extensions are defined in IIS.
  • The ISAPI “aspnet_isapi” loads the Http Runtime.
  • The Http Runtime creates an HttpContext and associates the request with an HttpApplication.
  • The request passes through the Http Pipeline. Http Modules are executed against the request until the request hits the ASP.NET page Http Handler.
  • Once the request leaves the Http Pipeline, the page life cycle starts.

[Update]

The viewstate and page life cycle article is now posted here

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

mohamad halabi


Team Leader, Netways
.NET and BizTalk Developer
MCSD.NET and MSF certified
Occupation: Team Leader
Company: Netways
Location: Lebanon Lebanon

你可能感兴趣的:(Architecture)