• home
  • forum
  • my
  • kt
  • download
  • The Application and HTTP Modules

    Author: 2007-07-05 08:53:59 From:

    After completing this tutorial, you will be able to
    • Use HttpApplication as a rendezvous point for your application
    • Manage data within the HttpApplication object
    • Manage events within the HttpApplication object
    • Work with HTTP Modules

    This tutorial covers working with application state and application-wide events within your ASP.NET application. In normal desktop applications, the notion of a global meeting place for various parts of an application is well-understood.

    After completing this tutorial, you will be able to

    • Use HttpApplication as a rendezvous point for your application

    • Manage data within the HttpApplication object

    • Manage events within the HttpApplication object

    • Work with HTTP Modules

    This tutorial covers working with application state and application-wide events within your ASP.NET application. In normal desktop applications, the notion of a global meeting place for various parts of an application is well-understood. For example, MFC, a C++ class library supporting low-level Windows development, includes a class named CWinApp that holds state useful throughout the program. This state includes such items as a handle to the current instance of the application, a handle to the main window, and the parameters that were passed in when the application started. The CWinApp class also runs the message loop¡ªsomething that can be done only within the global scope of a Windows application. A running Windows application contains one and only one instance of the CWinApp class, and it's perennially available from anywhere within the application.

    Windows Forms¡ªthe .NET library supporting Windows forms¡ªhas a similar class named Application. It includes the same sort of state (command line parameters, a top-level window, other state required by the program). The Windows Forms Application class also runs the message loop.

    Web development also requires the same sort of ¡°global space¡± that a desktop application requires. Having a global space within a Web application makes implementing features such as caching data and session state possible. Let's take a look at how ASP.NET implements a global space for Web applications.

    As we've seen so far, one of the most distinctive aspects of Web-based development is the requirement to be very mindful of the state of your application. By itself, raw Web application development includes no support for dealing with state. After all, Web requests are made over a disconnected protocol and the state of a request evaporates as soon as it hits an endpoint.

    In Tutorial 4 (all about server-side controls in depth), we took a look at the notion of view state within an ASP.NET application. ASP.NET server-side controls have the option of supporting view state. View state is embedded within the data going back and forth between the browser and the server and is used (most of the time) to keep the user interface appearing as though the browser and the server are connected continually. For example, without view state (or some special coding within the server), UI elements such as combo boxes lose their state between posts, causing the first item in the list to always show as the selected item¡ªeven if it wasn't really the item selected.

    In Tutorial 13, we looked at session state¡ªor the data accompanying a specific session. Session state is useful for items such as shopping carts where the application has to associate data with a client.

    Finally, in Tutorial 14, we took a look at caching state so as to avoid unnecessary round-trips to a data source. Loading data from memory is usually much faster than loading it from a database or regenerating it. When it comes to storing data that all parts of your application can use, the data must be stored somewhere else besides view state and session state. We saw that the cache is available from virtually anywhere in the application via the HttpContext object. The HttpContext includes a reference to an instance of the HttpApplication object. In addition to being a holding place for the cache, the application object has its own dictionary that serves as a useful place to hold data. It works in very much the same way the Cache does. However, there are some subtle yet important differences between the Cache and the dictionary held by HttpApplication.

    Keeping a dictionary and a data cache available for the rest of the application isn't the only good reason to implement a central application object. The other reason is to have a mechanism for handling application-wide events. We've seen that the Page class handles events for a request specifically. However, think about how the entire ASP.NET pipeline works. Some useful events aren't part of the page processing or request processing mechanism. Implementing those involves code working outside the normal page processing mechanism.

    For example, we looked at session state in Tutorial 13. When a request first comes through a site whose session state is enabled, when should the session object be set up? Certainly, you want it set up before the page-specific processing begins. In Tutorial 10 we saw the ASP.NET security model. When should authentication and authorization be handled? You want those things to happen outside the context of the normal request processing, too. A final example is output caching, as we saw in Tutorial 15. For output caching to work, ASP.NET needs to intercept the request when it first enters the pipeline so that it may bypass the whole page creation process and render the cached content instead.

    ASP.NET's HttpApplication object can manage these sorts of things. When running, the Http-Application object represents a rendezvous point for all the parts of your entire Web application. If you're looking for software patterns to identify within ASP.NET, the HttpApplication most closely represents the singleton pattern. You treat it as a single instance of an object within your application. A reference to it is accessible at any point in time through the HttpContext class via the Current property.

    Overriding the HttpApplication to include your own state and event handling is a matter of adding a file named Global.asax to your application. In fact, Visual Studio will add one to your application that is set up and ready to handle a few application-wide events. Remember from examining ASPX files that Page files include the Page directive at the top of the file. The Global.asax file includes a similar directive. The Application directive tells the runtime compiling machinery that this file is meant to serve as the application object.

    Listing 17-1 shows an example of the HttpApplication expressed within a file named Global.asax. The Global.asax provided by Visual Studio overrides the Application_Start, Application_End, Application_Error, Session_Start, and Session_End events.

    Listing 17-1

    <%@ Application Language="C#" %>
    
    <script runat="server">
    
        void Application_Start(Object sender, EventArgs e) {}
        void Application_End(Object sender, EventArgs e) {}
        void Application_Error(Object sender, EventArgs e) {}
        void Session_Start(Object sender, EventArgs e) {}
        void Session_End(Object sender, EventArgs e) {}
    
    </script>

    To get an idea as to how these events work, the following example illustrates placing a piece of data in the application's dictionary and retrieving it later when the page loads.

    Managing Application State

    1. Start a new Web site named UseApplication.

    2. Drag a GridView onto the default page. Don't assign a data source to it yet. You'll populate it with a data that is stored with the application in later steps.

    3. Add a Global.asax to the site. Right-click on the project in the Project Explorer (or select Web Site | Add New Item from the main menu). Choose the Global application template, as shown below.

      Graphic
    4. You've just added a file named Global.asax to your application. You can see that the Application_Start event is already handled (although it does nothing right now).

    5. To have some data to store with the application object, import the QuotesCollection from Tutorial 14. The project name is UseDataCaching. Select Web Site | Add Existing Item from the main menu and find the file QuotesCollection.cs. In addition to importing the QuotesCollection.cs file, grab the QuotesCollection.xml and QuotesCollection.xsd files from the UseDataCaching\App_Data directory.

    6. Add some code to the Application_Start event to load the quotes data and place it in the application dictionary. Server.MapPath will give you the path from which the application is executing so you can load the XML and XSD files. Storing the data in the dictionary is very much like adding it to the cache.

          void Application_Start(Object sender, EventArgs e) {
              QuotesCollection quotesCollection = new QuotesCollection();
      
                 String strAppPath = Server.MapPath("");
      
                 String strFilePathXml = 
                      strAppPath  + "\\app_data\\QuotesCollection.xml";
                String strFilePathSchema = strAppPath +
                       "\\app_data\\QuotesCollection.xsd";        
      quotesCollection.ReadXmlSchema(strFilePathSchema);        
      quotesCollection.ReadXml(strFilePathXml);
      
      Application["quotesCollection"] = quotesCollection;    
      }
    7. Update Page_Load method in the Default.aspx page to load the data from the application's dictionary. The application state is available through the page's reference to the Application object. Accessing data within the dictionary is a matter of indexing it correctly. After loading the data from the dictionary, apply it to the DataSource property in the GridView and bind the DataGrid.

          protected void Page_Load(object sender, EventArgs e)
          {
            QuotesCollection quotesCollection = 
               (QuotesCollection)Application["quotesCollection"];
      
            GridView1.DataSource = quotesCollection;
            GridView1.DataBind();
          }

    Application State Caveats

    As you can see, the application state and the cache seem to overlap in their functionality. Indeed, they're both available from similar scopes (from any point in the application), and getting the data in and out involves using the right indexer. However, the application state and the cache vary in a couple of significant ways.

    First, items that go into the application state stay in the cache until you remove them explicitly. The cache implements more flexibility in terms of setting expirations and other removal/refresh conditions.

    In addition, putting many items into the application dictionary will inhibit the scalability of your application. To make the application state thread-safe, the HttpApplicationState class has a Lock method. While using the Lock method will ensure the data is not corrupted, locking the application frequently will greatly reduce the number of requests it can handle.

    Ideally, data going into the application state should be read only once loaded¡ªor changed very infrequently. As long as you're aware of these issues, the application state can be a useful place to store information required by all parts of your application.

    Handling Events

    The other useful aspect of the application object is its ability to handle application-wide events. As we saw in the previous example, the Global.asax file is a handy place to insert event handlers. Visual Studio will insert a few for you when you simply add one to your application. Some events are handled only in Global.asax, while others may be handled outside Global.asax. The events for which Visual Studio generates stub handlers inside Global.asax include Application_Start, Application_End, Application_Error, Session_Start, and Session_End. Following is a rundown of these events.

    Application_Start

    Application_Start happens when the application is first initialized, that is, when the first request comes through. Because Application_Start happens first (and only once) during the lifetime of an application, the most common response for the event is to load and initialize data at the start of the application (as with the example above).

    Application_End

    The ASP.NET runtime raises Application_End as the application is shutting down. This is a useful place to clean up any resources requiring special attention for disposal.

    Application_Error

    Unfortunately, bad things sometimes happen inside Web applications. If something bad has happened in one of your existing applications, you may already have seen the standard pale yellow and red ASP.NET error page. Once you deploy your application, you probably don't want clients to see this sort of page. Intercept this event (Application_Error) to handle the error.

    Session_Start

    The Session_Start event occurs when a user makes an initial request to the application, which initializes a new session. This is a good place to initialize session variables (if you want to initialize them before the page loads).

    Session_End

    This event occurs when a session is released. Sessions end when they time out or when the Abandon method is called explicitly. This event happens only for applications whose session state is being held in-process.

    HttpApplication Events

    The events listed above are implemented in Visual Studio's default Global.asax. The application object can fire a number of other events. Table 17-1 shows a summary of all the events pumped through the application object.

    Table 17-1 Application-wide events.

    Event

    Reason

    Order

    Only in Global.asax

    Application_Start

    Application is spinning up.

    Start of app

    *

    Application_End

    Application is ending.

    End of app

    *

    Session_Start

    Session is starting.

    *

    Session_End

    Session is ending.

    *

    BeginRequest

    A new request has been received.

    1

    AuthenticateRequest/

    PostAuthenticateRequest

    The user has been authenticated, that is, the security identity of the user has been established.

    2

    AuthorizeRequest/

    PostAuthorizeRequest

    The user has been authorized to use the requests resource.

    3

    ResolveRequestCache/

    PostResolveRequestCache

    Occurs between authorizing the user and invoking handler. This is where the output caching is handled. If content is cached, the application can bypass the entire page rendering process.

    4

    AcquireRequestState/

    PostAcquireRequestState

    Occurs when session state needs to be initialized.

    5

    PreRequestHandlerExecute

    Occurs immediately before request is sent to the handler. This is a last-minute chance to modify the output before it heads off to the client.

    6

    PostRequestHandlerExecute

    Occurs following the content being sent to the client.

    7

    ReleaseRequestState/

    PostReleaseRequestState

    Occurs following request handling. This event occurs so the system may save state used if necessary.

    8

    UpdateRequestCache/

    PostUpdateRequestCache

    Occurs following handler execution. This is used by caching modules to cache responses.

    9

    EndRequest

    Fires after request is processed.

    10

    Disposed

    Occurs before the application shuts down.

    End of app

    Error

    Fired when an unhandled application error occurs.

    When an exception occurs

    PreSendRequestContent

    Fired before content sent to client.

    PreSendRequestHeaders

    Fired before HTTP headers sent to client.

    The following example shows how to time requests by intercepting the BeginRequest and the EndRequest events within Global.asax.

    Timing Requests

    1. Open up Global.asax within the UseApplication Web site.

    2. Add handlers for BeginRequest and EndRequest as shown below.

      Graphic

      Visual Studio will insert the following stubs in Global.asax:

          protected voidApplication_BeginRequest(object sender,
                   EventArgs e)
          {
      
          }
      
          protected void Application_EndRequest(object sender,
                   EventArgs e)
          {
      
          }
    3. Implement the BeginRequest handler by getting the current date and time and storing it within the Items property of the current HttpContext. The Items property is a name/value collection that you may index in the same way you index the cache, the session state, and the HttpApplication dictionary. Implement the EndRequest handler by comparing the time stamp obtained from the beginning of the request and comparing it to the current date and time. Print out the amount of time taken to process the request using Response.Write.

      protected void Application_BeginRequest(object sender, EventArgs e)
          {
      
              DateTime dateTimeBeginRequest = DateTime.Now;
      
              HttpContext ctx = HttpContext.Current;
              ctx.Items["dateTimeBeginRequest"] = dateTimeBeginRequest;
      
          }
      
          protected void Application_EndRequest(object sender, EventArgs e)
          {
              DateTime dateTimeEndRequest = DateTime.Now;
      
              HttpContext ctx = HttpContext.Current;
              DateTime dateTimeBeginRequest =
                   (DateTime)ctx.Items["dateTimeBeginRequest"];
      
              TimeSpan duration = dateTimeEndRequest - dateTimeBeginRequest;        
              Response.Write("<b> This request took " +
                  duration.ToString() + "</b></br>");
          }

      You should see the duration printed near the top of the response returned to the browser:

      Graphic


    Overriding Global.asax is a very convenient way to manage data and events within an application. Visual Studio generates a Global.asax for you and even stubs out the more important events for you. However, overriding Global.asax isn't the only way to store state and handle application-wide events. The other way is to write an HTTP Module.

    HTTP Modules serve very much the same role ISAPI filters served for classic ASP¡ªas a place to insert functionality into the request processing. HTTP Modules plug into the ASP.NET processing chain to handle application-wide events in the same way that Global.asax handles application-wide events. In fact, many ASP.NET features are implemented through HTTP Modules.

    Existing Modules

    ASP.NET employs HTTP Modules to enable features such as output caching and session state. To get an idea of what features are implemented via HTTP Modules, take a look at the master configuration file for your machine (that is, go to the Windows directory, look in the Microsoft.NET directory, and drill down to the configuration directory for the most current release). The master Web.Config file mentions several modules in the httpModules section of the configuration, as shown in Listing 17-2. This list does not include entire strong names of the assemblies, but it gives you an idea as to what modules are already part of the ASP.NET pipeline.

    Listing 17-2

    <httpModules>
     <add name="OutputCache"
      type="System.Web.Caching.OutputCacheModule" />
     <add name="Session"
      type="System.Web.SessionState.SessionStateModule" />
     <add name="WindowsAuthentication"
      type="System.Web.Security.WindowsAuthenticationModule" />
     <add name="FormsAuthentication"
      type="System.Web.Security.FormsAuthenticationModule" />
     <add name="PassportAuthentication"
      type="System.Web.Security.PassportAuthenticationModule" />
    <add name="RoleManager"
      type="System.Web.Security.RoleManagerModule" />
    <add name="UrlAuthorization"
      type="System.Web.Security.UrlAuthorizationModule" />
    <add name="FileAuthorization"
      type="System.Web.Security.FileAuthorizationModule" />
    <add name="AnonymousIdentification"
      type="System.Web.Security.AnonymousIdentificationModule" />
    <add name="Profile"
      type="System.Web.Profile.ProfileModule" />
    <add name="ErrorHandlerModule"
    type="System.Web.Mobile.ErrorHandlerModule " />
    </httpModules>

    The <httpModules> section mentions the name of a module, followed by a fully specified type that implements the feature. The following features are handled by modules:

    • Output Caching

    • Session State

    • Windows Authentication

    • Forms Authentication

    • Passport Authentication

    • Role Manager

    • URL Authorization

    • File Authorization

    • Anonymous Identification

    • Profile

    Tutorial 2 (¡°ASP.NET Application Fundamentals¡±) includes a short summary of the ASP.NET pipeline. The Modules fit into the processing chain and take effect prior to being processed by the HttpApplication object. While the features themselves may require extensive code to implement (for example, imagine all the work that went into the session state manager), the basic formula for hooking a module into your application is pretty straightforward. Creating a module involves four steps:

    1. Writing a class implementing IHttpModule

    2. Writing handlers for the events you want handled

    3. Subscribing to the events

    4. Mentioning the module in Web.Config

    Implementing a Module

    Here's an example illustrating how HTTP Modules work. The earlier example in this tutorial demonstrated how to time requests by handling events within Global.asax. The example showed time stamping the beginning of a request, storing the time stamp in the current HttpContext, and examining the time stamp as the request finished.

    The following example performs the same functionality. However, the example uses an HTTP Module to handle the events.

    A Timing Module

    1. To implement a timing module, open the Web site solution file for this tutorial¡ªUse-Application. To work, the module needs to exist in an assembly. It's easiest to write a completely separate assembly for the module. Add a project to the solution by selecting File | Add | New Project from the main menu. Make the project a Class Library and name the project TimingModule.

    2. Visual Studio will add a class to the library named Class1. (The name of the file generated by Visual Studio is Class1.cs and the name of the class generated by Visual Studio is Class1). Change the name of the file to Timer.cs and the name of the class to Timer.

    3. The module as generated by Visual Studio doesn't understand the ASP.NET types. Add a reference to System.Web to make the ASP.NET types available.

    4. Add handlers for the beginning and ending of the request. You may borrow the code from Global.asax if you want to. The signatures for the event's handlers are such that the methods need to return void and accept two arguments: an object and EventArgs.

      using System;
      using System.Data;
      using System.Configuration;
      using System.Web;
      /// <summary>
      /// Summary description for Timer
      /// </summary>
      public class Timer
      {
         public Timer()
         {
         }
      
         public void OnBeginRequest(object o, EventArgs ea)
         {
            HttpApplication httpApp = (HttpApplication)o;
      
            DateTime dateTimeBeginRequest = DateTime.Now;
      
            HttpContext ctx;
            ctx = HttpContext.Current;
            ctx.Items["dateTimeBeginRequest"] = dateTimeBeginRequest;
         }
      
         public void OnEndRequest(object o, EventArgs ea)
         {
            HttpApplication httpApp = (HttpApplication)o;
      
            DateTime dateTimeEndRequest = DateTime.Now;
      
            HttpContext ctx;      
            ctx = HttpContext.Current;
            DateTime dateTimeBeginRequest =
               (DateTime)ctx.Items["dateTimeBeginRequest"];
      
      
            TimeSpan duration = dateTimeEndRequest - dateTimeBeginRequest;
      
      
            ctx.Response.Write("<b> This request took " +
               duration.ToString() + "</b></br>");
         }
      }
    5. Add IHttpModule to the class's inheritance list. Add implementations for the methods Init and Dispose. The job performed by Init is to subscribe to events. The job performed by Dispose is to release any resources used by the module (Dispose doesn't need to do anything in this example).

      using System;
      using System.Data;
      using System.Configuration;
      using System.Web;
      
      /// <summary>
      /// Summary description for Timer
      /// </summary>
      public class Timer :
               IHttpModule
      {
         public Timer()
         {
         }
      
         public void Init(HttpApplication httpApp)
         {
      
            httpApp.BeginRequest +=
               new EventHandler(this.OnBeginRequest);
      
            httpApp.EndRequest +=
               new EventHandler(this.OnEndRequest);
            }
            public void Dispose() { }
      
      // ¡­
      }
    6. By default, the output produced by the compiler is directed to a separate binary and debug directory (that is, it doesn't go in a place where the Web site can use it). To make the assembly available to the Web site, you need to redirect the output of the compiler so it goes in the Web site's bin directory. To add a \Bin folder to the Web site project, right-click on the Web site project in Project Explorer and select Add Folder. Select Bin folder. Then right-click on the Timer project again and select Properties. On the property page, redirect the compiler output to the bin directory for the Web site. You can do this in the Build properties for the TimerModule project. If you created this as an IIS Web site, the bin directory will be directly under the project's IIS virtual directory. The following graphic shows the Visual Studio dialog for changing the target path.

      Graphic
    7. Finally, mention the TimerModule in the Web.Config file. It needs to appear within the <httpModules> section, nested within the <system.web > section, like so:

      <configuration>
       <system.web>
           <httpModules>
            <add name="TimingModule"
                 type="Timer, TimingModule" />
           </httpModules>
      </system.web>
      </configuration>

    As long as the TimerModule assembly is available to your application (that is, it's in the \bin subdirectory of your virtual directory), it will be linked into the processing chain.

    See Active Modules

    We saw above that many ASP.NET features are implemented through modules. While you can see the modules listed within the master configuration file, you can also see the list of available modules at runtime. They're available through the current application instance. The following exercise illustrates how to do this.

    Listing the Modules

    1. Add a button to the Default.aspx page of the UseApplication solution. This button will list the attached modules, so give it a Text property of Show Modules. Also add a list box to the page that will show the modules.

      Graphic
    2. Double-click on the button to add a handler within the page.

    3. Handle the button event by grabbing the list of modules from the application instance. The list comes back as a collection that you can apply to the list box's DataSource property. Calling DataBind on the ListBox will put the names of all the modules in the ListBox.

      protected void ButtonShowmodules_Click(object sender, EventArgs e)
      {
      
          HttpApplication httpApp = HttpContext.Current.ApplicationInstance;
          HttpModuleCollection httpModuleColl = httpApp.Modules;
      
          Response.Write("<br>");
          String[] rgstrModuleNames;
          rgstrModuleNames = httpModuleColl.AllKeys;
      
          this.ListBox1.DataSource = rgstrModul eNames;
          this.ListBox1.DataBind();
         }

      Running the page and clicking the Show Module button will fill the list box with a list of modules plugged into the application (check out the TimingModule entry in the list).

      Graphic

    Storing State in Modules

    HTTP Modules are also a very handy place to store global state for your application. The following example shows how to track the average request duration (which requires storing the duration of each request as part of application state).

    Tracking Average Request Duration

    1. Before inserting the functionality into the module, let's think a bit about how to use the information about the average request duration. You might use it to profile and to find bottlenecks in your application. While sending the information out to the client browser is always useful, there might be times when you want to use the information programmatically. To retrieve the information from the Module, you'll need to add one or more methods (above and beyond the Init and Dispose methods) to the Timer-Module. The best way to do that is to define an interface that has functions you can use to talk to Module. The following listing defines an interface for retrieving the average request duration. Create a file named ITimerModule.cs and add it to the Timer Module subproject.

      using System;
      public interface ITimerModule
      {
         TimeSpan GetAverageLengthOfRequest();
      }
    2. Implement the ITimer interface within the Timer class. Include a reference to the TimerModule in the Default.aspx page so the page code has access to the interface. Include an ArrayList in the Timer class to hold on to durations of the requests. Store the duration of the request at the end of each request (in the OnEndRequest handler). Use clock ticks as the measurement to make it easier to compute the average duration. Finally, implement GetAverageLengthOfRequest (the method defined by the ITimerModule interface) by adding all the elements in the ArrayList and dividing that number by the size of the Array-List. Create a TimeSpan using the result of the calculation and return that to the client.

      public class Timer : IHttpModule,
                                           ItimerModule{
         public Timer()
         {
         }
      
         protected ArrayList _alRequestDurations =
            new ArrayList();
         public void Init(HttpApplication httpApp)
         {
            httpApp.BeginRequest +=
               new EventHandler(this.OnBeginRequest);
            httpApp.EndRequest +=
               new EventHandler(this.OnEndRequest);
         }
         public void Dispose() { }
      
         public void OnBeginRequest(object o, EventArgs ea)
         {
            HttpApplication httpApp = (HttpApplication)o;
      
            DateTime dateTimeBeginRequest = DateTime.Now;
      
            HttpContext ctx;
            ctx = HttpContext.Current;
            ctx.Items["dateTimeBeginRequest"] = dateTimeBeginRequest;
         }
      
         public void OnEndRequest(object o, EventArgs ea)
         {
            HttpApplication httpApp = (HttpApplication)o;
      
            DateTime dateTimeEndRequest = DateTime.Now;
      
            HttpContext ctx;
            ctx = HttpContext.Current;
            DateTime dateTimeBeginRequest =
               (DateTime)ctx.Items["dateTimeBeginRequest"];
      
            TimeSpan duration =
                     dateTimeEndRequest - dateTimeBeginRequest;
      
            ctx.Response.Write(
                     "<b> From the Timing module; this request took " +
            duration.Duration().ToString() + "</b></br>");
            _alRequestDurations.Add(duration);
         }
         public TimeSpan GetAverageLengthOfRequest()
         {
           long lTicks = 0;
           foreach (TimeSpan timespanDuration in this._alRequestDurations)
           {
                lTicks += timespanDuration.Ticks;
           }    
      
           long lAverageTicks = lTicks / _alRequestDurations.Count;
           TimeSpan timespanAverageDuration = new TimeSpan(lAverageTicks);
           return timespanAverageDuration;
         }
      }
    3. Now add some code in the Default.aspx page to examine the average time taken to process each request. Add a button to fetch the average duration, and a label to display the average duration. Give the button a caption something like ¡°Show Average Duration Of Requests¡±:

      Graphic
    4. Double-click on the Show Average Duration Of Requests button to add a handler for it. Handle the event by fetching the TimerModule from the collection of Modules. You can fetch it by name because the collection is indexed on the module name (as specified in Web.Config).

         protected void
               ButtonShowAverageDurationOfRequests_Click(
                     object sender,
                     EventArgs e)
         {
            HttpApplication httpApp =
                     HttpContext.Current.ApplicationInstance;
      
            HttpModuleCollection httpModuleColl = httpApp.Modules;
            IHttpModule httpModule =
                     httpModuleColl.Get("TimingModule");
            ITimerModule timerModule =
                     (ITimerModule)httpModule;
      
            TimeSpan timeSpanAverageDurationOfRequest =
               timerModule.GetAverageLengthOfRequest();
            LabelAverageDurationOfRequests.Text =
                     timeSpanAverageDurationOfRequest.ToString();
         }

      The object you get back by accessing the module collection is an HTTP Module. To be able to talk to it using the ITimerModule interface, you need to cast the reference to the Module. Once you do that, you may call GetAverageLengthOfRequest and display it in the label:

      Graphic

    To see how the timing module might look in Visual Basic, see Listing 17-3.

    Listing 17-3

    Imports
    System
    Imports System.Collections
    Imports Timer
    Imports System.Web
    Public Class TimingModuleVB : Implements IHttpModule
    
        Protected _alRequestDurations As New ArrayList()
    
        Public Sub Init(ByVal httpApp As HttpApplication) _
         Implements IHttpModule.Init
            AddHandler httpApp.BeginRequest, _
              New EventHandler(AddressOf OnBeginRequest)
    
            AddHandler httpApp.EndRequest, _
              New EventHandler(AddressOf OnEndRequest)
    
        End Sub
    
        Public Sub Dispose() Implements IHttpModule.Dispose
        End Sub
    
        Private Sub OnBeginRequest(ByVal src As Object, _
          ByVal e As EventArgs)
            Dim httpApp As HttpApplication
            httpApp = CType(src, HttpApplication)
    
            Dim dateTimeBeginRequest As DateTime
            dateTimeBeginRequest = DateTime.Now
    
            Dim ctx As HttpContext
            ctx = HttpContext.Current
            ctx.Items("dateTimeBeginRequest") = dateTimeBeginRequest
        End Sub
    
        Private Sub OnEndRequest(ByVal src As Object, _
          ByVal e As EventArgs)
            Dim httpApp As HttpApplication
            httpApp = CType(src, HttpApplication)
    
            Dim dateTimeEndRequest As DateTime
            dateTimeEndRequest = DateTime.Now
    
            Dim ctx As HttpContext
            ctx = HttpContext.Current
    
            Dim dateTimeBeginRequest As DateTime
    
            dateTimeBeginRequest = _
              CType(ctx.Items("dateTimeBeginRequest"), DateTime)
    
            Dim duration As TimeSpan
            duration = dateTimeEndRequest - dateTimeBeginRequest
            ctx.Response.Write( _
             "<b> From the Timing module; this request took ")
            ctx.Response.Write( _
              duration.Duration().ToString() + "</b></br>")
    
            _alRequestDurations.Add(duration)
        End Sub
    
        Function GetAverageLengthOfRequest() As TimeSpan
            Dim lTicks As Long = 0
    
            Dim timespanDuration As TimeSpan
    
            For Each timespanDuration In _
              Me._alRequestDurations
                lTicks = lTicks + timespanDuration.Ticks
            Next
    
            Dim lAverageTicks As Long
    
            lAverageTicks = lTicks / _alRequestDurations.Count
            Dim timespanAverageDuration As TimeSpan
            timespanAverageDuration = _
              New TimeSpan(lAverageTicks)
            Return timespanAverageDuration
    
        End Function
    
    End Class
    Both the application object expressed through Global.asax and HTTP Modules offer a rendezvous point for your application. You can use both of them to store global state between requests as well as respond to application-wide events. When choosing one over the other, remember that Global.asax really goes with your application. Global.asax is intended to manage state and events specific to your application. HTTP Modules exist as completely separate assemblies. They're not necessarily tied to a particular application, and may even be signed and deployed in the Global Assembly Cache. That makes Modules an ideal vehicle for implementing generic functionality that's useful between different applications.

    In this tutorial, we saw how the ASP.NET architecture includes a rendezvous point for all the requests passing through an application. This is especially important in Web applications composed of disparate components centered around a pipeline. While there are certain obvious places where a request context can show up (most notably in the end handler), it's clear that there are other points in the request chain where you need to have something to hold on to.

    ASP.NET offers two broad choices in implementing such a ¡°global space.¡± Global.asax is a convenient representation of the HttpApplication object. ASP.NET applications have a singular instance of the HttpApplication class. The application object includes a handy dictionary in which to store data that needs to survive and be available from all points within the application. In addition, Global.asax offers a place to intercept various application-wide events.

    HTTP Modules offer very much the same functionality, although in a different package. HTTP Modules implement the IHttpModule interface and are deployed with the application via the Web.Config file. When an application starts up, the ASP.NET runtime looks in the Web.Config file to see if any additional handlers need to be attached to the pipeline. (ASP.NET plugs in a number of Modules already¡ªthey implement such features as authentication and session state.) When ASP.NET sees a new Module within the Web.Config file, ASP.NET loads the Module and calls the Init method. Modules usually initialize by setting up handlers for various application-wide events.

    To

    Do This

    Create a custom module assembly

    Create a new class implementing IHttpModule

    Override Init

    Override Disposet

    Insert the module into the processing chain

    Mention the module in the <httpModule> node of the application's Web.Config file

    Handle application events in the module

    Write a handler (within the module) for every event you want to handle

    During the Init method, subscribe to the events by attaching the event handlers to the events

    Override the application object in Global.asax file

    Select Web site | Add New Item

    Select Global Application Template from the templates

    Insert your own code for responding to the application-wide events

    Use the application's dictionary

    Access the application object (it's always available from the current HttpContext). Use the indexer notation to access the dictionary

    discuss this topic to forum

    relation tutorial

    No relevant information

    Category

      NET (110)

    New

    Hot