20.2 Controlling the ApplicationNow that an application has been defined, you will see how applications can be controlled globally. There are two ways of doing this: using the HttpApplication object and using the global.asax file. 20.2.1 HttpApplication ObjectJust as a web page instantiates the Page class, when an application runs, it instantiates an object from the HttpApplication class. This object has methods, properties, and events that are available to all the objects within the application. It provides several objects that allow you to interact with the HTTP request. These include:
ASP.NET maintains a pool of HttpApplication instances during the lifetime of each application. Every time a page is requested from the server, an HttpApplication instance is assigned to it. This instance manages the request from start to end. Once the request is completed, that instance is freed up for reuse. You can program against the HttpApplication object by using a file called global.asax, described in the next section. 20.2.2 global.asaxAny code contained in the global.asax file becomes part of the application in which it is located There can be only a single global.asax file per application, located in the virtual root directory of the application. However, this file is optional. If there is no global.asax file, then the application will run using default behavior for all the events exposed by the HttpApplication class.
When the application runs, the contents of global.asax are compiled into a class that derives from the HttpApplication class. Thus, all the methods, classes, and objects of the HttpApplication class are available to your application. The CLR monitors global.asax for changes. If it detects a change in the file, the application is automatically stopped and restarted. This starts a new application domain. Any requests that are currently being handled by the old application domain are allowed to complete, but any new requests are handled by the new application domain. When the last request on the old application domain is finished, that application domain is removed. This effectively reboots the web application without any users being aware of the fact. To prevent application users from being able to see the code underlying the application, ASP.NET is configured by default to prevent users from seeing the contents of global.asax. If someone enters the following URL in a browser: http://localhost/progaspnet/Global.asax they will receive a 403 (forbidden) error message or an error message similar to the following: This type of page is not served.
The global.asax file looks and is structured very similarly to a page file (.aspx). It can have one or more sections, which will be described in detail shortly. The sections are:
Just as web pages and web services can use code-behind, the global.asax file can also use code-behind. In fact, similar to web pages and web services, the default behavior of Visual Studio .NET is to use the code-behind technique with global.asax. It creates a default global.asax file in the application root. The Application directive in that global.asax file (which is analogous to the Page directive in the page file and will be described fully in the next section of this chapter) has an Inherits property that points to the code-behind class created in global.asax.vb or global.asax.cs, depending on your language. A sample global.asax file is shown in Example 20-1 in VB.NET and in Example 20-2 in C#. Note that, in order to use this example, the ASP.NET account must have the permission to access the root directory c:\ (which isn't recommended in a production system). Example 20-1. Sample global.asax in VB.NET<%@ Application Language="VB"%> <script runat="server"> protected sub Application_Start(ByVal Sender as Object, _ ByVal e as EventArgs) Application("strDSN") = _ "SERVER=Zeus;DATABASE=Pubs;UID=sa;PWD=secret;" dim Books( ) as string = {"SciFi","Novels", "Computers", _ "History", "Religion"} Application("arBooks") = Books WriteFile("Application Starting") end sub protected sub Application_End(ByVal Sender as Object, _ ByVal e as EventArgs) WriteFile("Application Ending") end sub sub WriteFile(strText as string) dim writer as System.IO.StreamWriter = _ new System.IO.StreamWriter("C:\test.txt",true) dim str as string str = DateTime.Now.ToString( ) & " " & strText writer.WriteLine(str) writer.Close( ) end sub </script> Example 20-2. Sample global.asax in C#<%@ Application Language="C#"%> <script runat="server"> protected void Application_Start(Object sender, EventArgs e) { Application["strDSN"] = "SERVER=Zeus;DATABASE=Pubs;UID=sa;PWD=secret;"; string[] Books = {"SciFi","Novels", "Computers", "History", "Religion"}; Application["arBooks"] = Books; WriteFile("Application Starting"); } protected void Application_End(Object sender, EventArgs e) { WriteFile("Application Ending"); } void WriteFile(string strText) { System.IO.StreamWriter writer = new System.IO.StreamWriter(@"C:\test.txt",true); string str; str = DateTime.Now.ToString( ) + " " + strText; writer.WriteLine(str); writer.Close( ); } </script> 20.2.2.1 DirectivesAs with web page and web service files, the global.asax file begins with zero, one, or more application directives. These are used to specify settings to be used by the application compilers when they process the ASP.NET files. Just like page directives, application directives use a dictionary structure that accepts one or more attribute/value pairs. There are three supported directives: Application, Import, and Assembly. ApplicationThe Application directive specifies application-specific attributes used by the compiler. A sample Application directive might look something like this: <%@ Application Language="VB" Inherits="WebServiceConsumer.Global" Description="A sample application" %> The Language attribute can have any of the standard language values: VB, C#, JS, or VJ# for VB.NET, C#, JScript .NET, or J#, respectively. (Any third-party language that supports the .NET platform can also be used.) The default is C#. The language specified here applies only to the language used in the global.asax file, not to any of the other code files in the application. It is perfectly legal to use C# in the global.asax file and VB.NET in the .aspx file, or vice versa, for example. The Inherits attribute specifies the name of a class to inherit from. When Visual Studio .NET creates a global.asax file, it uses this attribute to specify the name of the class created in the code-behind file. The Description attribute will accept a text description of the application, which is then ignored by the parser and compiler. The CodeBehind attribute is used only by Visual Studio .NET to keep track of the file that contains the code-behind. The ClassName attribute is used to assign a name to the class generated by the code in the global.asax file. This class name can then be used for identifying global static variables and instance methods, as will be shown later. ImportThe Import directive takes a single attribute, a namespace. The specified namespace is explicitly imported into the application, making all its classes and interfaces available. The imported namespace can either be part of the .NET Framework or a custom namespace. A typical Import directive might look like this: <%@ Import Namespace="System.Data" %> There can be only a single Namespace attribute. If you need to import multiple namespaces, use multiple Import directives. The following namespaces are automatically imported into all web applications and so do not need an Import directive: System System.Collections System.Collections.Specialized System.Configuration System.IO System.Text System.Text.RegularExpressions System.Web System.Web.Caching System.Web.Security System.Web.SessionState System.Web.UI System.Web.UI.HtmlControls System.Web.UI.WebControls AssemblyThe Assembly directive links an assembly to the current application during compilation. This makes all the assembly's classes and interfaces available to the application. Using the Assembly directive enables both early binding and late binding, since the assembly can be referenced at compile time, then loaded into the application domain at runtime. Assemblies that are physically located in the application assembly cache (i.e., the \bin directory) are automatically linked to the application. Therefore, any assembly located in the \bin directory does not need to be linked with an Assembly directive. There are two possible attributes for the Assembly directive: Name and Src. Name is a string with the name of the assembly to link to the application. It should not include a path. Src is the path to a source file that will be dynamically compiled and linked. Each Assembly directive can have only a single attribute. If you need to link to multiple assemblies, use multiple Assembly directives. Assembly directives will look something like this: <%@ Assembly Name="SomeAssembly" %> <%@ Assembly Src="SomeSourceFile.cs" %> 20.2.2.2 Script blocksThe typical global.asax file will contain the bulk of its code in a script block. In Example 20-1 and Example 20-2, this would include all the code contained between the script tags: <script runat="server"> . . . </script> If using code-behind, the code contained within the code-behind class in the code-behind file is equivalent to putting the code in a script block, although code in the code-behind file itself is not enclosed by script tags. The code contained within the script block can consist of event handlers, methods, or static variables. All of these are described in the following sections. In Example 20-1 and Example 20-2, the script block contains two event handlers, Application_Start and Application_End, plus a public method, WriteFile. EventsJust as web pages and the controls that they contain expose events that can be handled by the CLR, the application and sessions running under the application also expose events. These events can be handled by event handlers contained in the global.asax file. For example, the Application_Start event is fired when the application starts, and the Application_End event is fired when the application ends. Some of the application events fire every time a page is requested, while others, such as Application_Start or Application_Error, only fire under certain conditions. The Application_Start event is fired when the application starts and the Application_End event is fired when the application ends. The sample global.asax file shown in Example 20-1 and Example 20-2 demonstrates event handlers for these two events. The Application_Start event in Example 20-1 and Example 20-2 sets two Application properties: a string called strDSN and an array of strings called arBooks. The event handler then calls a method, WriteFile, which is also contained within the global.asax file. This method writes a line to a log file with a message that the application is starting. The WriteFile method is a very simple logging method. It opens a StreamWriter object on a text file, hard-coded to be c:\test.txt. It adds a line to the file containing a timestamp and whatever text string is passed in to the method. The Boolean parameter true in the StreamWriter method call specifies that if the file already exists, the line will be appended to the file. If the file does not exist, it is created. The Application_End event handler simply makes another call to WriteFile to make a log entry that the application has ended. To see the results of these two event handlers, make some meaningless edit to global.asax and save the file. This will force the application to end. Then request any URL in the virtual directory that contains the global.asax file. For this example, use one of the web pages from a previous chapter—it doesn't really matter which one—or even a very simple web page of your own creation. Example 20-3 shows an excerpt from the resulting log file. Example 20-3. Excerpt from Test.txt8/26/2001 5:46:23 PM Application Starting 8/26/2001 6:13:35 PM Application Ending 8/27/2001 10:17:39 PM Application Starting 8/27/2001 10:18:23 PM Application Ending 8/27/2001 10:18:36 PM Application Starting Just as there are Start and End events for the Application, there are Start and End events for each session, Session_Start and Session_End. This allows you to have code that will run every time every session within the application starts and ends. By putting an event handler in global.asax for every possible application event, as shown in Example 20-4 for VB.NET and Example 20-5 for C#, it is easy to see the cycle of application events as the page request is received, processed, and rendered. Example 20-4. global.asax event demonstration in VB.NET<%@ Application Language="VB" %> <script runat="server"> protected sub Application_Start(ByVal Sender as Object, _ ByVal e as EventArgs) WriteFile("Application Starting") end sub protected sub Application_End(ByVal Sender as Object, _ ByVal e as EventArgs) WriteFile("Application Ending") end sub protected sub Session_Start(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Session_Start" + "<br/>") end sub protected sub Session_End(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Session_End" + "<br/>") end sub protected sub Application_Disposed(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_Disposed" + "<br/>") end sub protected sub Application_Error(ByVal Sender as Object, _ ByVal e as EventArgs) dim strError as string strError = Server.GetLastError().ToString( ) Context.ClearError( ) Response.Write("Application_Error" + "<br/>") Response.Write("Error Msg: " & strError + "<br/>") end sub protected sub Application_BeginRequest(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_BeginRequest" + "<br/>") end sub protected sub Application_EndRequest(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_EndRequest" + "<br/>") end sub protected sub Application_AcquireRequestState(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_AcquireRequestState" + "<br/>") end sub protected sub Application_AuthenticateRequest(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_AuthenticateRequest" + "<br/>") end sub protected sub Application_AuthorizeRequest(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_AuthorizeRequest" + "<br/>") end sub protected sub Application_PostRequestHandlerExecute(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_PostRequestHandlerExecute" + "<br/>") end sub protected sub Application_PreRequestHandlerExecute(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_PreRequestHandlerExecute" + "<br/>") end sub protected sub Application_PreSendRequestContent(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_PreSendRequestContent" + "<br/>") end sub protected sub Application_PreSendRequestHeaders(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_PreSendRequestHeaders" + "<br/>") end sub protected sub Application_ReleaseRequestState(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_ReleaseRequestState" + "<br/>") end sub protected sub Application_ResolveRequestCache(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_ResolveRequestCache" + "<br/>") end sub protected sub Application_UpdateRequestCache(ByVal Sender as Object, _ ByVal e as EventArgs) Response.Write("Application_UpdateRequestCache" + "<br/>") end sub sub WriteFile(strText as string) dim writer as System.IO.StreamWriter = _ new System.IO.StreamWriter("C:\test.txt",true) dim str as string str = DateTime.Now.ToString( ) & " " & strText writer.WriteLine(str) writer.Close( ) end sub </script> Example 20-5. global.asax event demonstration in C#<%@ Application Language="C#" %> <script runat="server"> protected void Application_Start(Object sender, EventArgs e) { WriteFile("Application Starting"); } protected void Application_End(Object sender, EventArgs e) { WriteFile("Application Ending"); } protected void Session_Start(Object sender, EventArgs e) { Response.Write("Session_Start" + "<br/>"); } protected void Session_End(Object sender, EventArgs e) { Response.Write("Session_End" + "<br/>"); } protected void Application_Disposed(Object sender, EventArgs e) { Response.Write("Application_Disposed" + "<br/>"); } protected void Application_Error(Object sender, EventArgs e) { string strError; strError = Server.GetLastError().ToString( ); Context.ClearError( ); Response.Write("Application_Error" + "<br/>"); Response.Write("Error Msg: " + strError + "<br/>"); } protected void Application_BeginRequest(Object sender, EventArgs e) { Response.Write("Application_BeginRequest" + "<br/>"); } protected void Application_EndRequest(Object sender, EventArgs e) { Response.Write("Application_EndRequest" + "<br/>"); } protected void Application_AcquireRequestState(Object sender, EventArgs e) { Response.Write("Application_AcquireRequestState" + "<br/>"); } protected void Application_AuthenticateRequest(Object sender, EventArgs e) { Response.Write("Application_AuthenticateRequest" + "<br/>"); } protected void Application_AuthorizeRequest(Object sender, EventArgs e) { Response.Write("Application_AuthorizeRequest" + "<br/>"); } protected void Application_PostRequestHandlerExecute(Object sender, EventArgs e) { Response.Write("Application_PostRequestHandlerExecute" + "<br/>"); } protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e) { Response.Write("Application_PreRequestHandlerExecute" + "<br/>"); } protected void Application_PreSendRequestContent(Object sender, EventArgs e) { Response.Write("Application_PreSendRequestContent" + "<br/>"); } protected void Application_PreSendRequestHeaders(Object sender, EventArgs e) { Response.Write("Application_PreSendRequestHeaders" + "<br/>"); } protected void Application_ReleaseRequestState(Object sender, EventArgs e) { Response.Write("Application_ReleaseRequestState" + "<br/>"); } protected void Application_ResolveRequestCache(Object sender, EventArgs e) { Response.Write("Application_ResolveRequestCache" + "<br/>"); } protected void Application_UpdateRequestCache(Object sender, EventArgs e) { Response.Write("Application_UpdateRequestCache" + "<br/>"); } void WriteFile(string strText) { System.IO.StreamWriter writer = new System.IO.StreamWriter(@"C:\test.txt",true); string str; str = DateTime.Now.ToString( ) + " " + strText; writer.WriteLine(str); writer.Close( ); } </script> The following are all the events fired with every page request, in the order in which they are fired:
The following are the application events that fire only under certain conditions:
You can handle specific error conditions where necessary in your code, using try.. catch blocks. You can also trap for errors at the page level using the ErrorPage attribute of the Page directive. Any errors handled in these ways will not trigger the Application_Error event. To test this new version of global.asax, create the simple web page shown in Example 20-6 for VB.NET or Example 20-7 for C#. In the C# version of the code listing in Example 20-7, only the script block is shown, since the HTML is identical to the VB.NET version. When this web page is run, you will typically see something similar to the screen shot shown in Figure 20-4. Example 20-6. Web page demonstrating application events in VB.NET, vbGlobalEvents-01.aspx<%@ Page Language="VB" %> <script runat="server"> sub btnEndSession_Click(ByVal Sender as Object, _ ByVal e as EventArgs) Session.Abandon( ) end sub</script> <html> <body> <form runat="server"> <h1>Global Events</h1> <asp:Button id="btnEndSession" Text="End Session" OnClick="btnEndSession_Click" runat="server"/> </form> </body> </html> Example 20-7. Web page demonstrating application events in C#, csGlobalEvents-01.aspx<%@ Page Language="C#" %> <script runat="server"> void btnEndSession_Click(Object Source, EventArgs E) { Session.Abandon( ); } </script> Figure 20-4. Viewing global eventsIn Figure 20-4, you see that a series of application events have fired. About midway through the page, the .aspx file itself is finally rendered, followed by another series of application events. Notice that the first time the page is displayed, the Session_Start event is fired, but on subsequent displays, the Session_Start event may not be fired. This is because the request is part of the same session. Clicking on the End Session button causes the Session.Abandon method to be called, which ends the current session. The next time the page is submitted to the server, the Session_Start event will again be fired. Most of the Application event handlers in Example 20-4 and Example 20-5 use the Response.Write method to indicate that the event has been called. However, the Application_Start and Application_End methods call the WriteFile method instead. If you try using Response.Write in these event handlers, they will not display on the web page because the session in which the page is to be rendered is not running. However, by examining the log file, c:\test.txt, you will see entries that indicate when the application starts and ends. The sample global.asax file shown in Example 20-4 and Example 20-5 demonstrates one way of using the Application_Error event. That code is reproduced here for reference. In VB.NET, it is: protected sub Application_Error(ByVal Sender as Object, _ ByVal e as EventArgs) dim strError as string strError = Server.GetLastError().ToString( ) Context.ClearError( ) Response.Write("Application_Error" + "<br/>") Response.Write("Error Msg: " & strError + "<br/>") end sub In C#, it is: protected void Application_Error(Object sender, EventArgs e) { string strError; strError = Server.GetLastError().ToString( ); Context.ClearError( ); Response.Write("Application_Error" + "<br/>"); Response.Write("Error Msg: " + strError + "<br/>"); } This event handler uses the HttpServerUtility object's GetLastError method to report the last error that occurred. That error is converted to a string and assigned to a string variable: strError = Server.GetLastError().ToString( ) Next the HttpContext object's ClearError method is called to clear all the errors for the current HTTP request: Context.ClearError( ) If the errors are not cleared, then the error will still display on the client browser and the subsequent Response.Write statements will never be visible. Finally the Response.Write statements display a message and the current error to the client browser. An alternative technique for reporting an error to the user would display a custom error handling page. To do this, replace the Response.Write lines in the Application_Error event handler with the following line of code in C#: Response.Redirect("CustomErrorPage.aspx?Msg=" + Server.UrlEncode(strError)); In VB.NET, use the following: Response.Redirect("CustomErrorPage.aspx?Msg=" & _ Server.UrlEncode(strError)) This line of code uses the HttpServerUtility object's UrlEncode method to pass the error message as a query string parameter to the custom error page coded in CustomErrorPage.aspx. CustomErrorPage.aspx would have a label control, called lblMessage, and the following code in its Page_Load method (in C#): void Page_Load(Object Source, EventArgs E) { lblMessage.Text = Request.QueryString(Msg); } 20.2.2.3 Global static variables and instance methodsIt was noted previously that the code contained in the global.asax file is compiled into a class derived from HttpApplication and becomes part of the application. You can assign a name to this compiled class by using the ClassName attribute of the Application directive. In VB.NET, the Application directive then looks something like the following: <%@ Application Language="VB" ClassName="ProgAspNet"%> In C#, it might look like this: <%@ Application Language="C#" ClassName="ProgAspNet"%> Once a name has been assigned to the class, it can be referred to throughout the application, making available global static variables and instance methods. Static member variables are those variables that do not require that the class containing the variable be instantiated. Static member variables are defined using the Shared keyword in VB.NET, and with the static keyword in C#. Public methods can also be defined using either the VB.NET Shared keyword or the C# static keyword, in which case they do not require that the class of which the method is a member be instantiated in order to invoke the method. For example, given the following Application directive in global.asax: <%@ Application Language="C#" ClassName="ProgAspNet"%> a method named SomeMethod defined in global.asax can be invoked anywhere in the application with the following line of code: ProgASPNet.SomeMethod( ); Methods can also be instance methods; that is, they can be called from an object instance. For example, given the following Application directive in global. asax: <%@ Application Language="VB" ClassName="ProgAspNet"%> the following code invokes the method (in VB .NET): Dim oProg As New ProgAspNet oProg.SomeMethod( ) To see how global static variables and instance methods defined in global.asax can be made available throughout an ASP.NET application, make the following modifications to the global.asax files in either Example 20-4 or Example 20-5:
To demonstrate the use of global static variables and global instance methods, access the sample web page shown in Example 20-8 (for VB.NET) or Example 20-9 (for C#). The pages are similar to those shown in Example 20-6 and Example 20-7, respectively, with the code changes highlighted. In the C# version of the code listing in Example 20-9, only the script block is shown, since the HTML is identical to the VB. NET version. Example 20-8. Global static variable and instance method demonstration web page in VB.NET, vbGlobalEvents-02. aspx<%@ Page Language="VB" %> <script runat="server"> sub Page_Load(ByVal Sender as Object, _ ByVal e as EventArgs) lblGlobalStatic.Text = ProgAspNet.successRate.ToString( ) + " %" dim p as new ProgAspNet p.WriteFile("Now in Page_Load of web page.") end sub sub btnEndSession_Click(ByVal Sender as Object, _ ByVal e as EventArgs) Session.Abandon( ) end sub</script> <html> <body> <form runat="server"> <h1>Global Events</h1> Global Static Variable: <asp:Label id="lblGlobalStatic" runat="server"/> <br/> <asp:Button id="btnEndSession" Text="End Session" OnClick="btnEndSession_Click" runat="server"/> </form> </body> </html> Example 20-9. Global static variable and instance method demonstration web page in C#, csGlobalEvents-02.aspx<%@ Page Language="C#" %>
<script runat="server">
void Page_Load(Object Source, EventArgs E)
{
lblGlobalStatic.Text = ProgAspNet.successRate.ToString( ) + " %";
ProgAspNet p = new ProgAspNet( );
p.WriteFile("Now in Page_Load of web page.");
}
void btnEndSession_Click(Object Source, EventArgs E)
{
Session.Abandon( );
}
</script>
Once the class name has been assigned and a static variable is declared in global.asax, referencing the static variable is as simple as prepending the class name to the variable name using dot notation, as in: lblGlobalStatic.Text = ProgAspNet.successRate.ToString( ) + " %"; The ToString method must be called to convert the variable to a string so that it can be concatenated with a string literal and assigned to the Text property of the label. Calling the instance method is slightly more involved, since the class must first be instantiated. In VB.NET the following line of code instantiates the class: dim p as new ProgAspNet In C#, that is accomplished with the following line: ProgAspNet p = new ProgAspNet( ); Once the class has been instantiated, the WriteFile method is called using dot notation. In VB.NET, the line is: p.WriteFile("Now in Page_Load of web page.") In C#, it's: p.WriteFile("Now in Page_Load of web page."); 20.2.2.4 Server-side includesExternal source code files can be included in the application using server-side includes. The code contained within an include file is added to global.asax before it is compiled. The language used in the include file must match the language used in the global.asax file, although that may be different from the language(s) used within the application. The syntax for a server-side include is identical for both VB.NET and C#: <!--#Include PathType="fileName" --> In this syntax, PathType can have one of two values, shown in Table 20-1.
Looking at the sample global.asax listed in Example 20-1 or Example 20-2, add the following line as the second line in the file: <!--#Include File="IncludeFile.vb" --> or: <!--#Include File="IncludeFile.cs" --> depending on your language. Create a new text file, called either IncludeFile.vb or IncludeFile.cs, and store it in the same directory that contains global.asax. This file requires a pair of script tags, just like the global.asax file itself. Move a copy of the WriteFile method from global.asax to the include file. Finally, comment out (or delete) the WriteFile method from global.asax. The include file should look like Example 20-10 or Example 20-11, depending on the language. Example 20-10. Include file for global.asax in VB.NET<script runat="server" > Public sub WriteFile(strText as string) dim writer as System.IO.StreamWriter = _ new System.IO.StreamWriter("C:\test.txt",true) dim str as string str = DateTime.Now.ToString( ) & " " & strText writer.WriteLine(str) writer.Close( ) end sub </script> Example 20-11. Include file for global.asax in C#<script runat="server"> public void WriteFile(string strText) { System.IO.StreamWriter writer = new System.IO.StreamWriter(@"C:\test.txt",true); string str; str = DateTime.Now.ToString( ) + " " + strText; writer.WriteLine(str); writer.Close( ); } </script> If you run any of your web pages, there should be no difference in behavior, because all you did was move the code for a method from one file to another. Just as the CLR watches for changes in global.asax and restarts the application if any occur, it also watches for changes in any include files. If an include file changes, then the application restarts for that as well. Include files are very useful for including the same standard code into multiple applications. This common code could include such things as methods for database access, writing log entries, error handling routines, logins, or any number of infrastructure-type pieces that are part of every application. 20.2.2.5 Object declarationsOne additional way to include code in the global.asax file is as declarative object tags. These static objects are declared as either Application objects or Session objects. They are then available for the duration of either the application or each session. Here is a code snippet showing how an object might be declared in the global.asax file. This snippet would be located outside the script block in the file: <object id="strDSN"
class="System.String"
scope="Application"
runat="server"/>
The object in this snippet can be referred to in the application by the value of the id attribute, which in this example is strDSN. The class attribute specifies the type of this object. In this case, it is a string object. The class attribute implies that the object is derived from a .NET assembly. Alternatively, you can use either a progid or classid instead of the class attribute to instantiate a COM object rather than a .NET object. Each object declaration can have only one of either class, progid, or classid. In this snippet, the scope attribute specifies that this will be an Application object. The other legal value for this attribute is Session. Objects declared in this way are not actually created upon declaration. They are created the first time they are referenced in the application. To reference the static object shown in the code snippet above in your code, refer to: Application("strDSN") It is also possible to store application or session information elsewhere, such as in the web.config file, which will be described in the next section. |