Browse DevX
Sign up for e-mail newsletters from DevX


A Low-level Look at ASP.NET Architecture : Page 4

Many developers are familiar only with the high-level .NET frameworks like Web Forms and Web services that sit at the very top level of the ASP.NET hierarchy. This article discusses the lower-level aspects of ASP.NET and explains how requests move from Web Server to the ASP.NET runtime and then through the ASP.NET HTTP pipeline to process requests.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

HttpRuntime, HttpContext, and HttpApplication—Oh My!
When a request hits, it is routed to the ISAPIRuntime.ProcessRequest() method. This method in turn calls HttpRuntime.ProcessRequest that does several important things (look at System.Web.HttpRuntime.ProcessRequestInternal with Reflector):

  • Creates a new HttpContext instance for the request
  • Retrieves an HttpApplication instance
  • Calls HttpApplication.Init() to set up pipeline events
  • Init() fires HttpApplication.ResumeProcessing(), which starts the ASP.NET pipeline processing
First, a new HttpContext object is created and passed the ISAPIWorkerRequest that wraps the ISAPI ECB. This context is available throughout the lifetime of the request and always accessible via the static HttpContext.Current property. As the name implies, the HttpContext object represents the context of the currently active request, because it contains references to all the vital objects you typically access during the request lifetime: Request, Response, Application, Server, and Cache. At any time during request processing HttpContext.Current gives you access to all of these objects.

The HttpContext object also contains a very useful Items collection that you can use to store data that is request specific. The context object gets created at the begging of the request cycle and released when the request finishes, so data stored there in the Items collection is specific only to the current request. A good example is a request logging mechanism where you want to track start and end times of a request by hooking the Application_BeginRequest and Application_EndRequest methods in Global.asax as shown in Listing 3. HttpContext is your friend—you'll use it liberally if you need data in different parts of the request or page processing.

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

Master of Your Domain: HttpApplication
Each request is routed to an HttpApplication object. The HttpApplicationFactory class creates a pool of HttpApplication objects for your ASP.NET application depending on the load on the application and hands out references for each incoming request. The size of the pool is limited to the setting of the MaxWorkerThreads entry in the machine.config file's ProcessModel key, which by default is 20.

The pool starts out with a smaller number though, usually one, and it then grows as multiple simultaneous requests need to be processed. The pool is monitored so that under load it may grow to its maximum number of instances, and later scaled back to a smaller number as the load drops.

HttpApplication is the outer container for your specific Web application. It maps to the class that 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 for the HTTP pipeline, 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
The HttpApplication is like a master of ceremonies—it is where the processing action starts
Each of these events is also implemented in the Global.asax file via empty methods that start with an Application_ prefix, for example, Application_BeginRequest(), or Application_AuthorizeRequest(). These handlers are provided for convenience since they are frequently used in applications, so that you don't have to explicitly create the event handler delegates.

It's important to understand that each ASP.NET virtual application runs in its own AppDomain and that inside of the AppDomain are multiple HttpApplication instances running simultaneously, fed out of a pool that ASP.NET manages. This is so that multiple requests can process at the same time without interfering with each other.

Figure 5. AppDomain, Application Pool, and Request Thread Interactions: Using a couple of browser instances, you can see how AppDomains, application pool instances, and request threads interact. When multiple requests fire you'll see the thread and application IDs change, but the AppDomain stays the same.
To see the relationship between the AppDomain, threads, and the HttpApplication, check out the code in Listing 4, which is part of the sample code. You can see the running form in Figure 5. To check this out, run two instances of a browser and then hit this sample page and watch the various IDs.

You'll notice that the AppDomain ID stays steady while thread and HttpApplication IDs change on most requests, although they likely will repeat. HttpApplications run out of a collection and are reused for subsequent requests, so the IDs repeat at times. Note though that an application instance is not tied to a specific thread—rather, an instance is assigned to the active executing thread of the current request.

Threads are served from the .NET ThreadPool and by default are Multithreaded Apartment (MTA) style threads. You can override this apartment state in ASP.NET pages with the ASPCOMPAT="true" attribute in the @Page directive. ASPCOMPAT is meant to provide COM components a safe environment to run in, and ASPCOMPAT uses special Single Threaded Apartment (STA) threads to service those requests. STA threads are set aside and pooled separately, because they require special handling.

The fact that these HttpApplication objects are all running in the same AppDomain is very important. This is how ASP.NET can guarantee that changes to web.config or individual ASP.NET pages get recognized throughout the AppDomain. Making a change to a value in web.config causes the AppDomain to be shut down and restarted. This makes sure that all instances of HttpApplication see the changes made because when the AppDomain reloads it re-reads the changes from ASP.NET at startup. Any static references are also reloaded when the AppDomain starts, so if the application reads values from App Configuration settings these values also get refreshed.

To see this in the sample, hit the ApplicationPoolsAndThreads.aspx page and note the AppDomain ID. Then go in and make a change in web.config (add a space and save). Then reload the page. You'll l find that a new AppDomain has been created.

In essence the Web Application/Virtual completely "restarts" when this happens. Any requests that are already in the pipeline processing will continue to run through the existing pipeline, while any new requests coming in get routed to the new AppDomain. To avoid the problem of "hung requests," ASP.NET forcefully shuts down the AppDomain after the request timeout period is up even if requests are still pending. So it's actually possible for two AppDomains to exist for the same HttpApplication at a given point in time (when an old one's shutting down and a new one is ramping up). Both AppDomains continue to serve their clients until the old one has run out its pending requests and shuts down, leaving just the new AppDomain running.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date