Tuesday, June 14, 2011

ASP.Net Internals- How asp.net page request gets processed

This article discusses what exactly happens behind the scene when an aspx (ASP.Net page) request comes to web server from the browser. Here I am discussing how IIS 6.0 handles the request, I have also mentioned IIS 5's way of handling the request.
  • Request comes to web server from web browser.
  • Once the request reaches IIS, it is detected by the http.sys kernel mode driver.
When you create a new IIS website, IIS registers the site with http.sys, which then receives all 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. for example, once the request reaches “myserver”, http.sys picks up the request. Let us say that “myapplication” is configured to run under the application pool “myapplicationpool”; in this case, http.sys inspects the request queue of “myapplicationpool” and forwards the request to the worker process under which “myapplicationpool” is running.
  • The request is forwarded to the application pool. 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 run by the worker – the “w3wp.exe”. So now, the worker process takes over.
Application Pools are a big improvement for IIS 6, as they allow very granular control over what executes in a given process. Application Pools can be configured 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 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.
  • The worker process “w3wp.exe” looks up the URL of the request in order to load the correct ISAPI extension. 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 the processing of the request starts.


















  
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 which can range 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 worker processes ASPNET_WP.EXE (IIS5) and W3WP.EXE (IIS6) host the .NET runtime (ASP.Net Runtime/HttpRuntime) and the ISAPI DLL calls into small set of unmanged interfaces via low level COM that eventually forward calls to an instance subclass of the ISAPIRuntime class. IsapiRuntime.ProcessRequest() called by non-managed code.
  • Each virtual directory gets its own AppDomain and within that AppDomain the ISAPIRuntime exists from which the bootstrapping process for an individual application starts.
  • IsapiRuntime.ProcessRequest() method calls HttpRuntime.ProcessRequest that does several important things:
    1. Creates a new HttpContext instance for the request
HttpContext 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.
    1. Once the Context has been set up, ASP.NET needs to route your incoming request to the appropriate application/virtual directory by way of an HttpApplication object. Every ASP.NET application must be set up as a Virtual (or Web Root) directory and each of these ‘applications’ are handled independently. HttpRuntime uses HttpApplicationFactory class to load an 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 AppDomain space – and you have an HttpApplication object assigned for your request.
HttpApplication is the outer container for your specific Web application and it maps to the class that is defined in Global.asax. It’s the first entry point into the HTTP Runtime that you actually see on a regular basis in your applications. If you look in Global.asax (or the code behind class) you’ll find that this class derives directly from HttpApplication:
public class Global : System.Web.HttpApplication
HttpApplication’s primary purpose is to act as the event controller of the Http Pipeline and so its interface consists primarily of events. The event hooks are extensive and include:
BeginRequest
AuthenticateRequest
AuthorizeRequest
ResolveRequestCache
AquireRequestState
PreRequestHandlerExecute
…Handler Execution…
PostRequestHandlerExecute
ReleaseRequestState
UpdateRequestCache
EndRequest
  • Inside the Http pipeline: Both HttpModules and HttpHandlers are loaded dynamically via entries in Web.config and attached to the event chain. HttpModules are actual event handlers that hook specific HttpApplication events, while HttpHandlers are an end point that gets called to handle ‘application level request processing’. HttpModules can inspect the incoming request and make decisions that affect the internal flow of the request. After passing through the specified HTTPModules, the request reaches an HTTP Handler, whose job it is to generate the output that will be sent back to the requesting browser.
    • Incase of aspx page the request now is passed to ‘PageHandlerFactory’ handler. 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.

    In a nut shell:
    • IIS gets the request
    • Looks up a script map extension and maps to aspnet_isapi.dll
    • Code hits the worker process (aspnet_wp.exe in IIS5 or w3wp.exe in IIS6)
    • .NET runtime is loaded
    • IsapiRuntime.ProcessRequest() called by non-managed code
    • IsapiWorkerRequest created once per request
    • HttpRuntime.ProcessRequest() called with Worker Request
    • HttpContext Object created by passing Worker Request as input
    • HttpApplication.GetApplicationInstance() called with Context to retrieve instance from pool
    • HttpApplication.Init() called to start pipeline event sequence and hook up modules and handlers
    • HttpApplicaton.ProcessRequest called to start processing
    • Pipeline events fire
    • Handlers are called and ProcessRequest method are fired
    • Control returns to pipeline and post request events fire



















    In 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.