3. Seeing Active Modules
Many ASP.NET
features are implemented through modules. Although you can see the
modules listed in the master configuration file, you can also see the
list of available modules at run time. They're available through the
current application instance. The following exercise illustrates how to
view the active modules.
Listing the modules
Add a button to the Default.aspx page of the UseApplication solution, as shown in the following graphic. Assign its ID to be ButtonShowmodules. This button will list the attached modules, so set its Text property to Show Modules. Also, add a list box to the page that will show the modules.
Double-click the button to add a Click event handler to the page.
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 = rgstrModuleNames;
this.ListBox1.DataBind();
}
Run the page and click the
Show Module button to fill the list box with a list of modules plugged
into the application, as shown in the following graphic. Check out the TimingModule entry in the list.
4. Storing State in Modules
HTTP modules are also very handy places 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
Before
inserting the functionality into the module, think about how to use the
information about the average request duration. You might use it to
profile and to find bottlenecks in your application. Although 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 need to add one or more
methods (above and beyond the Init and DisposeTimingModule.
The best way to do that is to define an interface that has functions
you can use to talk to the module. The following code defines an
interface for retrieving the average request duration. Create a file
named ITimingModule.cs and add it to the TimerModule subproject: methods) to the
public interface ITimingModule
{
TimeSpan GetAverageLengthOfRequest();
}
Implement the ITimingModule interface in the Timer class. Include an ArrayList in the Timer class to hold on to durations of the requests. (You need to add the System.Collections namespace to the list of using directives.) 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 ITimingModule interface) by adding all the elements in the ArrayList and dividing that number by the size of the ArrayList. Create a TimeSpan using the result of the calculation and return that to the client.
using System.Collections;
public class Timer : IHttpModule, ITimingModule
{
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)
{
DateTime dateTimeBeginRequest = DateTime.Now;
HttpContext ctx;
ctx = HttpContext.Current;
ctx.Items["dateTimeBeginRequest"] = dateTimeBeginRequest;
}
public void OnEndRequest(object o, EventArgs ea)
{
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 TimingModule: 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;
}
}
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 add a label to display the average duration. Give the
button the Text value Show Average Duration Of Requests, as shown in the following graphic, and the ID ButtonShowAverageDurationOfRequests. The label should have an empty Text value and the ID LabelAverageDurationOfRequests. Also, include a reference to the TimingModule in the Default.aspx page so that the page code has access to the interface.
Double-click the Show Average Duration Of Requests button in Visual Studio to add a Click event handler. Handle the event by fetching the TimingModulemodules. You can fetch it by name because the collection is indexed by module name (as specified in web.config). from the collection of
using TimingModule;
...
protected void
ButtonShowAverageDurationOfRequests_Click(
object sender,
EventArgs e)
{
HttpApplication httpApp =
HttpContext.Current.ApplicationInstance;
HttpModuleCollection httpModuleColl = httpApp.Modules;
IHttpModule httpModule =
httpModuleColl.Get("TimingModule");
ITimingModule TimingModule =
(ITimingModule)httpModule;
TimeSpan timeSpanAverageDurationOfRequest =
TimingModule.GetAverageLengthOfRequest();
LabelAverageDurationOfRequests.Text =
timeSpanAverageDurationOfRequest.ToString();
}
The object you get back by accessing the module collection is an HttpModule. To be able to talk to it using the ITimingModule interface, you need to cast the reference to the module. After you do that, you can call GetAverageLengthOfRequest and display it in the label, as shown in the following graphic: