You might not have thought of your ASP.NET pages as an actual application. It is an easy assumption to make because the pages are loosely connected groups of text files. We typically think of traditional applications as an executable (.exe) file, potentially with other supporting files, such as DLLs or .inf files. An ASP.NET application is different because a user can enter it from any page there's no fixed starting point and most associated files are readable by humans.
In reality, every virtual directory in IIS is very much an application. Regardless of which page is requested, the application starts the first time a page is requested. While users move from page to page, processing occurs in the background to handle the application. It can crash and be restarted just as any traditional application. The difference is that while a traditional application is started and run on a desktop computer allowing the user direct interaction, an ASP.NET application is started and run on a Web server, and a user must use a browser to access it.
IIS allows you to specify which virtual directories are applications. By default, IIS does not automatically make virtual directories applications. To do so, go into the Internet Service Manager, right-click on a virtual directory, and select Properties. In the Directory tab, under Application Settings, note the application that the virtual directory belongs to. To create an application from this directory, click on Create.
Remember that everything in the .NET Framework is an object. That includes ASP.NET applications. The HttpApplication object provides methods, properties, and events, just as ASP.NET pages and server controls do. Revisiting the previous paragraph, you can now infer that whenever a page in your virtual directory is requested for the first time, an HttpApplication object is instantiated.
Note that the application starts only the first time any page in your virtual directory is requested for the first time. This does not mean the first time a new page is requested. For example, if your application consisted of two files?TT>default.aspx and exit.aspx the application would start the first time either of these files is requested, not the first time each of the pages is requested. The former implies the application starts once, whereas the latter implies that the application starts every time a new page is requested.
So, how do you control the HttpApplication object (and thus your ASP.NET application)? The processing that occurs in each individual page accomplishes a certain task or tasks, but doesn't really control the application as a whole. One page cannot directly affect another. There must be a central location that controls the execution of the application. Enter global.asax.
The global.asax file is known as the ASP.NET application file. This file allows you to program against the HttpApplication object you can control the ASP.NET application as you do any other object through its methods and events (you'll examine how to do this after some more background discussion).
Note that the global.asax file is completely optional. If you do not create one for your application, the program operates in the default manner, with just enough processing to get things done. If you want to perform any additional functionality, however, you'll need this file.
The global.asax file is placed in the root directory of your ASP.NET application. For example, if you've been following the examples in this book, you should have created the virtual directory http://localhost/tyaspnet21days, which corresponds to the physical directory c:\inetpub\wwwroot\tyaspnet21days. This directory, by default, is not an application in itself; rather, the parent application is the c:\inetpub\wwwroot directory. The global.asax file then goes into this \wwwroot directory, and controls the application operation. Placing your global.asax file in the \tyaspnet21days directory will do no good unless this directory is marked as an application in the Internet Service Manager (see the note a few paragraphs back on how to do this).
ASP.NET configures this file so that it is not accessible from a browser. That way hackers cannot break in and modify your application. If someone tries to type www.yoursite.com/global.asax into his browser, he'll receive an error shown in Figure 18.2.
Figure 18.2. Requesting global.asax from the browser produces an error.
As mentioned earlier, global.asax is managed by the .NET Framework. Whenever this file has been modified, the CLR detects it and causes the application to restart so that the new settings can take effect. This can be a hassle for users, so modify this file sparingly.
The HttpApplication Class
You already know that the HttpApplication object allows you to control your ASP.NET application, but how does global.asax fit in? At runtime, global.asax is compiled into a dynamic class which is derived from the HttpApplication class. Thus, you can use the global.asax file to access objects and events that are available to the parent HttpApplication object.
During application initialization, a number of HttpApplication instances are created, and each instance handles one particular HTTP request at a time. It handles all processing of that request, and after it finishes, it can then be assigned another request. That instance is responsible for managing that particular request throughout its lifetime.
Imagine that you own an exclusive upscale restaurant, with waiters who serve only one table at a time. When a new customer comes in, one waiter is in charge of meeting all the customer's needs, such as seating, informing about the specials, and meal delivery (even though your meal might actually be delivered by someone else, the waiter is in charge of when that happens). In the same way, an HttpApplication instance handles the "welcoming" of the HTTP request, taking note of any request variables, and rendering the page (note that the actual rendering is done by an HttpHandler, but the HttpApplication instance tells it when to go).
Because the global.asax class is derived from the HttpApplication class, it inherits many of the latter's methods and events. Those methods and events provide the programmatic access for your ASP.NET application. In global.asax, then, you define the handlers that take care of the events raised by the HttpApplication instance, which all have to deal with the application processing. These methods must conform to standard event handler naming scheme: Application_EventName(event arguments). For example, Application_Start(Sender as Object, e as EventArgs).
The global.asax file operates in many ways similar to .aspx files. You can use page directives (@ Imports, @ Application, and @ Assembly), server-side includes (see tomorrow's lesson, "Separating Code from Content"), and code declaration blocks. You use global.asax to sync any event exposed by the HttpApplication class, as listed in Table 18.1 (you'll see many of these again in Day 20, "Debugging ASP.NET Pages").
Table 18.1. HttpApplication Class Events
|Event ||Description |
|AcquireRequestState ||Fired when the application obtains the cache for the request. |
|AuthenticateRequest ||Fired when the application tries to authenticate the HTTP request. |
|AuthorizeRequest ||Fired when the application tries to authorize the HTTP request. |
|BeginRequest ||Fired when the HTTP request starts. |
|EndRequest ||Fired when the HTTP request ends. |
|Error ||Fired when an error is raised. |
|PostRequestHandlerExecute ||Fired immediately after the HTTP handler processes the request. |
|PreRequestHandlerExecute ||Fired immediately before the HTTP handler processes the request. |
|PreSendRequestContent ||If the request contains additional content (querystring, form variables, and so on), this event is fired immediately before that content is received. |
|PreSendRequestHeaders ||Fired immediately before the request headers are received. |
|ReleaseRequestState ||Fired when the application releases the session state for the request. |
|ResolveRequestCache ||Fired when the application resolves the cache for the request. |
|UpdateRequestCache ||Fired when the application updates and releases the cache for the request. |
Take a look at a sample process. Listing 18.1 is your global.asax.
Listing 18.1 A Sample global.asax
1: <script language="VB" runat="server"> 2: 3: Sub Application_Start(Sender as Object, e as EventArgs) 4: Application("Time") = System.DateTime.Now 5: End Sub 6: 7: Sub Application_AcquireRequestState(Sender as Object, e as EventArgs) 8: Response.Write("Acquiring request session state ...<br>") 9: End Sub 10: 11: Sub Application_AuthenticateRequest(Sender as Object, e as EventArgs) 12: Response.Write("Authenticating request...<br>") 13: End Sub 14: 15: Sub Application_AuthorizeRequest(Sender as Object, e as EventArgs) 16: Response.Write("Authorizing request...<br>") 17: End Sub 18: 19: Sub Application_PostRequestHandlerExecute(Sender as Object, e as EventArgs) 20: Response.Write("Request handler executed...<br>") 21: End Sub 22: 23: Sub Application_PreRequestHandlerExecute(Sender as Object, e as EventArgs) 24: Response.Write("Request handler executed...<br>") 25: End Sub 26: 27: Sub Application_PreSendRequestContent(Sender as Object, e as EventArgs) 28: Response.Write("Receiving request content...<br>") 29: End Sub 30: 31: Sub Application_PreSendRequestHeaders(Sender as Object, e as EventArgs) 32: Response.Write("Receiving request headers...<br>") 33: End Sub 34: 35: Sub Application_ReleaseRequestState(Sender as Object, e as EventArgs) 36: Response.Write("Releasing request state...<br>") 37: End Sub 38: 39: Sub Application_ResolveRequestCache(Sender as Object, e as EventArgs) 40: Response.Write("Resolving request cache...<br>") 41: End Sub 42: 43: Sub Application_UpdateRequestCache(Sender as Object, e as EventArgs) 44: Response.Write("Updating request cache...<br>") 45: End Sub 46: 47: Sub Application_Error(Sender as Object, e as EventArgs) 48: Response.Write(Sender.Request.isAuthenticated & " is authenticating request.. .<br>") 49: End Sub 50: 51: Sub Session_Start(Sender as Object, e as EventArgs) 52: Response.Write("Session is starting...<br>") 53: End Sub 54: 55: Sub Application_BeginRequest(Sender as Object, e as EventArgs) 56: Response.Write("<b>Process</b><p>") 57: Response.Write("Request is starting...<br>") 58: End Sub 59: 60: Sub Application_EndRequest(Sender as Object, e as EventArgs) 61: Response.Write("Request is ending...<br>") 62: End Sub 63: 64: </script>
| || |
In this file, you provide functionality for most of the events listed in Table 18.1. In line 3, you use the HttpApplication object to record the application's start time for reference later (see Day 4, "Using ASP.NET Objects with C# and VB.NET," for more information on saving state). Each event then simply writes out a string to the page that tells you what it is doing this allows you to see the order in which the request is processed.
Save this file in the root folder?TT>c:\inetpub\wwwroot unless you've created an application out of your tyaspnet21days directory, in which case you can put the global.asax file there.
With the global.asax file presented in Listing 18.2, a short message will be output when each of the application-level events fires. Note that some of these events fire every single time an ASP.NET page is reviewed. To illustrate this, create the ASP.NET page shown in Listing 18.2.
Listing 18.2 Testing the global.asax Event Handlers
1: <%@ Page Language="VB" %> 2: 3: <script language="VB" runat="server"> 4: Sub Page_Load(Sender As Object, e As EventArgs) 5: lblOutput.text = "Page loading...<p>" & _ 6: "Application started at: " & Application("Time") & "...<br>" & _ 7: "Current time: " & DateTime.Now & "...<br>" 8: End Sub 9: 10: Sub Click(obj As Object, E As EventArgs) 11: Session.Abandon() 12: End Sub 13: </script> 14: 15: <html><body> 16: <form runat="server"> 17: <table align="center"> 18: <tr> 19: <td valign="top" width="300"><b>Output</b></td> 20: </tr> 21: <tr> 22: <td valign="top"> 23: <asp:label runat="server"/><p> 24: <asp:Button runat="server" 25: OnClick="Click" Text="End This Session"/> 26: </td> 27: </tr> 28: </table> 29: </form> 30: </body></html>
| || |
Save this file as Listing1802.aspx. This page, when requested, displays a few messages to the user, including the time the application started and the current time (shown on lines 5?). Line 25 contains a button control that, when clicked, abandons the current session. This will be useful to see how session is handled by the HttpApplication object. Figure 18.3 shows the output of the request.
Figure 18.3. The page produced by Listing 18.3.
When the page is first requested, several HttpApplication events fire, and the global.asax file handles them by outputting text. You can see the process of execution of the HttpApplication object on the left side of Figure 18.2, and the output from the Listing1802.aspx file on the right side. Notice how the output starts midway down the page; the application file processes the request and resolves the cache and session states, and then the HTTP request handler (I'll discuss those in the next section) takes over and produces the page output. Finally, the application file performs some additional functionality before the request is over. In other words, the methods execute in the following order:
The Page_Load event inside the .aspx file, followed by any other page outputs
Note that the exact events that execute might depend on the circumstances of the request to your page. For instance, if you request the page a second time, the Session_Start method won't execute, and consequently, you won't see Session is starting... as in Figure 18.3.
Notice the time discrepancy from the start of the application (as specified by the Application_Start method) to the actual rendering of the page (the actual time difference is dependent on your machine configuration). Subsequent requests won't take as long because the application is already started and the pages are compiled. Changing global.asax in any way will restart the application.
The End This Session button in Figure 18.3 uses the Abandon method of the Session object to restart the session and, consequently, causes Session is starting... to reappear.
Therefore, the global.asax file allows you to control nearly every aspect of the processing of an ASP.NET page. You can use HttpApplication object events to perform actions that are invisible to the user, such as authentication or other personalization the choices are yours.