IIS 6.0's use of http.sys


Wednesday, September 19, 2007

In IIS 6.0, incoming client requests are handled by the kernel-mode HTTP.sys driver.  Previous IIS versions used the user-mode Winsock driver, but IIS 6.0 enhances performance by using the kernel-mode HTTP.sys driver.  Kernel-mode drivers are more efficient than user-mode drivers because they provide direct access to the internal system resources.  On the other hand, user-mode drivers are less efficient but provide much better stability and security since they can only access the user address space.  In IIS 6.0, the kernel-mode HTTP.sys driver enhances performance in the areas of request routing, request queuing, and request caching.

HTTP.sys Routing and Queuing

Higher performance is achieved when a request is passed directly between a kernel-mode process and a user-mode process than when a request is passed between two user-mode processes.  HTTP.sys accomplishes this by playing a kernel-level proxy role between incoming client requests and user-mode worker processes. 

Worker processes are responsible for the actual processing of client requests.  When you write an ASP.NET application, the application is hosted within a user-mode worker process (or processes if you are running a web garden).  This worker process has a large pool of worker threads that can respond to HTTP.sys requests.  If all the threads within the worker process’s thread pool are in use, HTTP.sys’s kernel-level queue will be utilized to temporarily hold requests until a thread becomes available.  Heavy I/O activity is a common cause of worker thread pool depletion.  To explain this situation it is important to understand that the worker process also has a pool of I/O threads that are used to accomplish I/O operations such as file, web service, or database access.  Worker threads can get held up if they are waiting for I/O threads to finish processing heavy I/O operations.  This lack of worker threads will cause request queuing by HTTP.sys to kick in.  By the way, the HTTP.sys request queue can fill up making IIS respond back with 503 Server Not Available errors until threads become available once again.

To put it all together, when a new client request comes in and there are no available worker threads, HTTP.sys places the request in its kernel-level request queue.  This queue is tied to the application pool that is assigned to your ASP.NET application.  When a worker thread becomes available within the application pool's worker process(es), it pulls the request from the request queue and processes it.  When the worker process has completed processing the request, it utilizes HTTP.sys to respond back to the requesting client and returns the worker thread back into the thread pool.

A noteworthy benefit of worker processes being user-mode rather than kernel-mode can be seen in how instability is handled.  If an application hosted within a user-mode worker process crashes, requests are queued at the kernel level by HTTP.sys.  The server simply hands out a new worker process, and the queued requests continue to be processed.  Also, having worker processes run in user-mode protects the kernel from corruption and/or security violations that may be inherent to the ASP.NET application.

HTTP.sys Caching

Enhanced performance can also be seen in HTTP.sys’s ability to cache request responses.  This ability makes it possible for HTTP.sys to respond to requests directly and efficiently by not having to interact with the user-mode worker process when a particular request has already been handled and cached.

http.sys

8:18:18 PM   | asp.net |
 
asp.net page lifecycle events


Saturday, September 08, 2007

When writing asp.net code within a class that derives from System.Web.UI.Page (i.e., when creating a Web Form), it is important to understand the order in which the page's events fire. Being familiar with the page event lifecycle will allow you to make the best decision on when you can (and should) interact with page properties, controls, state, native resources, etc.

During the page lifecycle, events (e.g., Init, PreRender, etc.) are fired that trigger certain built-in functionality to happen. Developers can interact with these events and add their own customizations. There are two common practices for interacting with these page lifecycle events:

  1. Override the methods that raise these events. This is done by overriding the “On” methods (e.g., OnInit, OnPreRender, etc.) of the page.
  2. Add event handlers to the page. These event handlers will be called when the page's lifecycle events fire. The first step to making this work is to ensure that the AutoEventWireup="true" attribute exists in the @ Page directive. Next, simply use the Page_eventname syntax for each event that you want to intercept. You can see this in action with the default Page_Load method found on every newly created Web Form. So, the following two code examples would accomplish the same thing, with the second example requiring less typing:

    protected override void OnPreInit(EventArgs e)
    {
         this.PreInit += new EventHandler(_Default_PreInit);
         base.OnPreInit(e);
    }

    void _Default_PreInit(object sender, EventArgs e)
    {
        //custom code here
    }

    protected void Page_PreInit(object sender, EventArgs e)
    {
        //custom code here
    }

Below I have listed the most common page events in the order they occur and some information on what is going on when a particular event fires.

PreInit
When the PreInit event fires, personalization settings are initialized for the page. This is the appropriate time to dynamically change a page’s theme or master page.

base.MasterPageFile = "Main.master";

View state is not available yet.

Init
The Init event is responsible for setting up all declared server controls on the page. Because view state is not available yet, each control’s state is set to its default value. There are no guarantees as to the order in which controls will be initialized. Therefore, declared server controls cannot talk to each other at this time.

InitComplete
This event occurs once all controls have been initialized. At this point in the page lifecycle, you can access all declared server controls and dynamically created controls that were created in conjunction with the Init event. You will not be able to see any user inputted data since view state has not populated the controls yet.

PreLoad
At this point, postback and view state data has been loaded for each control on the page.

Load
This is the most well known event because Web Forms automatically create the Page_Load event handler for the Load event. At this point in the page lifecycle, all the controls on the page are loaded and setup with view state and postback data. This is a very common place for controls to be customized based on user input. Native resource calls (e.g., database access, file I/O, etc.) commonly reside in the Page_Load method as well.

Control Events
After the page’s load event has completed, any fired server control events are handled. For example, if a page has a Button control on it and a user presses the button, the event handler for the button press will occur at this point in the page lifecycle.

LoadComplete
All controls have been setup and control events handled at this point.

PreRender
PreRender occurs before the page’s controls are converted to HTML markup and sent out to the requesting browser. During the PreRender event, any controls that have their DataSourceID property set will have their DataBind method called. As an example, if you have a GridView that is data-bound to an ObjectDataSource, this is the point in the page lifecycle that the GridView will actually be filled with the ObjectDataSource’s SelectMethod data.

PreRenderComplete
At this point, pre-rendering has completed and the page is just about to be turned into an IO stream and sent out to the requesting browser. Since all controls that have their DataSourceID property set have now been filled with data, you can use this method to customize these data-bound controls. For example, you could add a custom ListItem to a DropDownList that is data bound to an ObjectDataSource.

SaveStateComplete
Right before this event is fired, all view state is saved for the page. If you try and make any changes to the page or its controls, they will be discarded.

Unload
At this late stage in the page lifecycle, the page is about to be unloaded from memory. This is a good time to do final clean-up operations like closing database connections or closing open files. This is also a great time to post log entries. The response stream is now closed, so you should not try to make calls into Response or you will get an exception.


10:43:56 AM   | c# | asp.net |