Section 18.3. Application-Wide Logic

18.3. Application-Wide Logic

All code contained in the page class is scoped to the page. In other words, it is only visible to other code within that page class. This is true for variables and members such as methods , properties, and events. For most code, this is the appropriate behavior. However, there are often situations where it is either convenient or necessary to have code scoped more globally. For example, you may have a common method used in several pages. Though you can replicate the code on all the pages, it is far better to have a single source. Another example would be an application where a variablea trackingID , for exampleis needed by every page as the user moves from page to page.

It is possible to scope your code application-wide (rather than per page). There are two ways of doing this: using the HttpApplication object and using the global.asax file.

18.3.1. HttpApplication Object

Just 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 available to all the objects within the application. It provides several objects that allow you to interact with the HTTP request:

  • The Application object for using application state

  • The Request object for getting access to the incoming request

  • The Response object for sending an HttpResponse back to the client

  • The Session object for access to session state

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 also program against the HttpApplication object by using a file called global.asax , described next .

18.3.2. global.asax

global.asax is a text file that provides globally available code. Such code can include event handlers for application and session events, methods, and static variables. This file is sometimes called an application file.

Any 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 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.

Classic ASP had a file with similar format and structure, called global.asa . In fact, if you copy all the code from a working copy of global.asa into global.asax , the application should run fine.


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, a new copy of the application will be automatically started, creating 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 seeing 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 

she will receive a 403 (forbidden) error message or an error message similar to the following:

 This type of page is not served. 

web.config files, described shortly, have behaviors similar to global.asax . If the file is changed, the application will automatically "restart". It is also not possible to view web.config files in a browser.


The global.asax file looks and is structured similarly to a page file ( .aspx ). It can have one or more sections, which will be described in detail shortly:

  • Directives

  • Script blocks

  • Object declarations

Just as web pages and web services can use code-behind, the global.asax file can use code-behind. However, unlike the situation with web pages and web services, the default behavior of VS2005 is not to use the code-behind technique with global.asax .

Versions of Visual Studio prior to 2005 by default did use the code-behind model with global.asax . Code-behind is still supported though not used by default.

To use code-behind with global.asax , the Application directive at the top of the file (which is analogous to the Page directive in a Page file, and will be described fully in the next section) has an Inherits property that points to the code-behind class created in global.asax.cs .

There is also a CodeBehind attribute which can be used to point to a code-behind file. However, if this points to a file located anywhere other than the App_Code folder, then the class file will have to be manually compiled.


You can add a global.asax file to a web application by right-clicking on the website in the Solution Explorer or clicking on the Website menu, and selecting Add New Item..., then selecting a Global Application Class. Leave the default name of global.asax .

VS2005 will create the file listed in Example 18-1. This boilerplate has empty declarations for five events: Application_Start and _End , Session_Start and _End , and Application_Error .

Example 18-1. Boilerplate global.asax
 <%@ Application Language="C#" %> <script runat="server">     void Application_Start(Object sender, EventArgs e) {         // Code that runs on application startup     }     void Application_End(Object sender, EventArgs e) {         //  Code that runs on application shutdown     }     void Application_Error(Object sender, EventArgs e) {         // Code that runs when an unhandled error occurs     }     void Session_Start(Object sender, EventArgs e) {         // Code that runs when a new session is started     }     void Session_End(Object sender, EventArgs e) {       // Code that runs when a session ends.       // Note: The Session_End event is raised only when the sessionstate       //       mode       // is set to InProc in the Web.config file. If session mode is set       //       to StateServer       // or SQLServer, the event is not raised.     } </script> 

The sample global.asax file listed in Example 18-2 sets some values in Application state and writes an entry to a log file every time the application starts. To use this example, the ASP.NET account must have permission to write to the root directory c:\ (which is not recommended in a production system).

Example 18-2. Sample global.asax
 <%@ Application  Language="C#"%> <script runat="server">    protected void Application_Start(Object sender, EventArgs e)    {       Application["strConnectionString"] =                     "SERVER=MyServer;DATABASE=Pubs;UID=myID;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> 

18.3.2.1. Directives

As with web page and web service files, the global.asax file may begin with any number of directives. These are used to specify settings to be used by the application compilers when they process the ASP.NET files. As with 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 .

Application . The Application directive specifies application-specific attributes used by the compiler. A sample Application directive might look something like this:

 <%@ Application  Language="C#" Inherits="WebServiceConsumer.Global"                Description="A sample application" %> 

The Language attribute can have any of the standard language values: VB , C# , JS , or VJ# for VB2005, 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 and not to any of the other code files in the application. It is perfectly legal to use C# in the global.asax file and VB2005 in the .aspx file, or vice versa, for example.

The Inherits attribute specifies the name of a class to inherit from, typically a class in a code-behind file.

The Description attribute accepts a text description of the application, which is then ignored by the parser and compiler.

The CodeBehind attribute was used by Visual Studio .NET (not VS2005) to keep track of the file that contains the code-behind.

Import . The 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 be part of the .NET Framework or a custom namespace.

A typical Import directive might look like this:

 <%@ Import Namespace="System.Data" %> 

There can only be one 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

Assembly . The Assembly directive links an assembly to the current application during compilation. This makes all the assembly's classes and interfaces available to the application.

Assemblies are, typically, .dll or .exe files and are described in detail in the next chapter.


Using the Assembly directive enables both early 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 (that is, the bin directory and code files located in the App_Code directory) are automatically linked to the application. Therefore, any assemblies located in the bin directory, or any assemblies compiled from code contained in the App_Code directory, need not 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 (relative only) to a source file that will be dynamically compiled and linked.

Each Assembly directive can only have one 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="sources/SomeSourceFile.cs" %> 

18.3.2.2. Script blocks

The typical global.asax file contains the bulk of its code in a script block contained between script tags:

 <script runat="server">     .     .     .     </script> 

If you are 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 or methods, as will be demonstrated in the following section.

18.3.2.3. Events

Just as web pages and the controls they contain expose events, 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, as well as in page-specific files. 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_Error , only fire under certain conditions.

The sample global.asax file shown in Example 18-2 demonstrates event handlers for the Application_Start and Application_End events. The Application_Start event in Example 18-2 sets two Application properties: a string called strConnectionString and an array of strings called arBooks . The event handler then calls a helper method, WriteFile , that is also contained within the global.asax file. This helper method writes a line containing the string argument to a log file. WriteFile is reproduced here from Example 18-2:

 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(  );     } 

The WriteFile method is a 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 will be created.

The Application_End event handler 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. For this example, use one of the web pages from a previous chapterit doesn't really matter which oneor a web page of your own creation. Example 18-3 shows an excerpt from the resulting log file.

Example 18-3. Excerpt from Test.txt
 8/26/2006 5:46:23 PM  Application Starting 8/26/2006 6:13:35 PM  Application Ending 8/27/2006 10:17:39 PM  Application Starting 8/27/2006 10:18:23 PM  Application Ending 8/27/2006 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 each session within the application starts and ends.

By putting an event handler in global.asax for every possible application event, as shown in Example 18-4 with all the method names highlighted for readability, it is easy to see the cycle of application events as the page request is received, processed , and rendered.

Example 18-4. global.asax event demonstration
 <%@ 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(  );       if (Context!= null)          Context.ClearError(  );       Response.Write("Application_Error" + "<br/>");       Response.Write("<b>Error Msg: </b>" + strError + "<br/>" +                      "<b>End Error Msg</b><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:



Application_BeginRequest

Raised for every request handled by ASP.NET. Code in this event handler is executed before the web page or service processes the request.



Application_AuthenticateRequest

Raised prior to authentication of the request. (As was covered in Chapter 12, authentication is the process whereby a user is verified as being who they say they are.) Code in this event handler allows custom security routines to be implemented.



Application_AuthorizeRequest

Raised prior to authorization of the request. (Authorization is the process of determining if the requesting user has permission to access a resource as discussed in Chapter 12.) Code in this event handler allows custom security routines to be implemented.



Application_ResolveRequestCache

Raised before ASP.NET determines whether the output should be generated fresh or filled from cache. Code in this event handler is executed in either case.



Application_AcquireRequestState

Raised prior to acquiring the session state.



Application_PreRequestHandlerExecute

Raised just prior to the request being passed to the handler that is servicing the request. After the event is raised, the page is processed by the HTTP handler processing the request.



Application_PostRequestHandlerExecute

Raised when the HTTP handler is finished with the page request. At this point, the Response object now has the data to send back to the client.



Application_ReleaseRequestState

Raised when the session state is released and updated.



Application_UpdateRequestCache

Raised when the output cache is updated, if the output is to be cached.



Application_EndRequest

Raised when the request is finished.



Application_PreSendRequestHeaders

Raised prior to sending the HTTP headers to the client. If response buffering is enabled, meaning that none of the data will be sent until all the data is ready (the default condition), this event will always follow Application_EndRequest . If response buffering is disabled, then this event will be raised whenever the data is sent back to the client. Response buffering is controlled by an attribute to a Page directive or, in the case of web services, a WebMethod attribute.



Application_PreSendRequestContent

Raised prior to sending the HTTP content to the client. As with Application_PreSendRequestHeaders , the order in which the event is raised depends on if response buffering is enabled.

The following are the application events that fire only under certain conditions:



Application_Start

Raised whenever the application is started. An application is started the first time any page is requested from an application virtual directory and the application is not already running.



Application_End

Raised whenever an application ends. An application ends whenever one of the configuration files ( global.asax , global.asax.cs , global.asax.vb , or web.config ) is modified, or the server is crashed or restarted. Cleanup code, such as closing database connections, is normally executed in this event handler.



Session_Start

Raised for every session that starts. This is a good place to place code that is session-specific.



Session_End

Raised for every session that ends. This provides an opportunity to save any data stored in session state.



Application_Disposed

Raised when the CLR removes the application from memory.



Application_Error

Raised whenever an unhandled error occurs anywhere in the application. This provides an excellent opportunity to implement generic application-wide error handling.

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 web page shown in Example 18-5. Call the website GlobalEvents . When this web page is run, you will get the screen shown in Figure 18-4.

Example 18-5. default.aspx for GlobalEvents
 <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs"    Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>Global Events</title> </head> <body>     <form id="form1" runat="server">     <div>       <h1>Global Events</h1>       <asp:Button ID="btnPost" runat="server" Text="Post" />       <asp:Button ID="btnEndSession" runat="server"                   Text="End Session"                   OnClick="btnEndSession_Click" />       <asp:Button ID="btnError" runat="server"                   Text="Generate Error"                   OnClick="btnError_Click" />     </div>     </form> </body> </html> 

Figure 18-4. GlobalEvents

In Figure 18-4, you see that a series of application events have fired. About midway through the sequence of events, the .aspx file itself is finally rendered, followed by another series of application events.

The GlobalEvents example must be run from an actual IIS virtual directory to behave properly.


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 fire.

The Post button simply provides a way to repost the page.

Most of the Application event handlers in Example 18-4 use the Response.Write method to indicate 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 18-4 demonstrates one way of using the Application_Error event. That code is reproduced here for reference:

 protected void Application_Error(Object sender, EventArgs e)     {        string strError;        strError = Server.GetLastError(  ).ToString(  );        if (Context!= null)           Context.ClearError(  );        Response.Write("Application_Error" + "<br/>");        Response.Write("<b>Error Msg: </b>" + strError + "<br/>" +                       "<b>End Error Msg</b><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, the error will still display on the client browser and the subsequent Response.Write statements will remain invisible.

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:

 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:

 void Page_Load(Object Source, EventArgs E)     {        lblMessage.Text = Request.QueryString["Msg"];     } 

The Generate Error button on Default.aspx intentionally causes an error to see error handling in action. The Click event handler for that button contains the following code, which will raise a Divide By Zero exception :

 protected void btnError_Click(object sender, EventArgs e)         {            int a = 5;            int b = 0;            int c;            c = a / b;         } 

18.3.2.4. Server-side includes

External 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 though that may be different from the language(s) used within the application.

The following syntax is used for a server-side:

 <!--#Include   PathType   ="   fileName   " --> 

In this syntax, PathType can have one of two values, as shown in Table 18-1.

Table 18-1. PathType attributes

Type of path

Description

File

fileName is a string containing a relative path from the directory containing the global.asax file.

Virtual

fileName is a string containing a full virtual path from a virtual directory in your web site.


Looking at the sample global.asax listed in Example 18-4, add the following line as the second line in the file:

 <!--#Include File="IncludeFile.cs" --> 

Create a new text file, called IncludeFile.cs and store it in the same directory that contains global.asax . This file requires a pair of script tags as with the global.asax file.

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 18-6.

Example 18-6. Include file for global.asax
 <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 will restart for that as well.

Include files are 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.

18.3.2.5. Object declarations

An additional way to include code in the global.asax file is as declarative object tags. These static objects are declared as either Application or Session objects. They are then available for the duration of 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 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 class , progid , or classid .

In this snippet, the scope attribute specifies this will be an Application object. The other legal value for this attribute is Session .

Objects declared in this way are not 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 the following:

 Application["strDSN"]; 

Storing application or session information elsewhere is also possible, such as in the web.config file, which will be described shortly.

18.3.3. Global Members

It 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 also create a separate class file that will contain globally available code, such as public member variables and methods. These global members can be either static or instance.

Static methods and member variables are those that do not require that the class containing the method or variable to be instantiated . Static member variables are defined using the static keyword in C#. Instance members require an instance of the class in order to be invoked. Any member not declared as static is an instance member. Both static and instance members will be demonstrated.

New to C# 2.0 is the static class, which contains only static members.


The trick to getting access to this global class is to place the class file in the App_Code directory under the application root. Placed there, it will automatically be compiled every time the application is run. (Alternatively, the class can be manually compiled and the resulting assembly located in the bin directory.) The class can then be referred to throughout the application, making available global static and instance members.

Version 1.x of ASP.NET provided a ClassName attribute of the Application directive, which allowed you to directly specify the name of the global class. That attribute is no longer supported in Version 2.0. Though it will not cause a compiler error, it will be ignored.


To see this in action, create a new web site in VS2005 called GlobalMembers. Right-click on the web site root folder in the Solution Explorer, or click on the Website menu item, and select Add Folder App_Code Folder. Then right-click on the new App_Code folder in the Solution Explorer and select Add New Item. From the Add New Item dialog, click on Class. Change the name to GlobalMembers.cs .

The name used for this file and for the name of the class within the file is not important as long as it is consistent throughout the application.


This class file will open in the editor with the class declared and an empty default constructor. Add the highlighted lines of code listed in Example 18-7.

Example 18-7. GlobalMembers.cs
 using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public class GlobalMembers {  public static   int successRate = 50;  public Global(  )    {    }  protected void Application_Start(Object sender, EventArgs e)    {       WriteFile("Application Starting");    }    protected void Application_End(Object sender, EventArgs e)    {       WriteFile("Application Ending");    }    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(  );    }    public static void StaticWriteFile(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(  );    }  } 

The first highlighted line of code in Example 18-7 implements a global static variable, called successRate . You can access this variable from anywhere in the application simply by pre-pending the class name. So, for example, if your web page has a Label control named lblGlobalStatic , you could set its Text property with the following line of code:

 lblGlobalStatic.Text = GlobalMembers.successRate.ToString(  ); 

The ToString method must be called to convert the variable to a string so it can be assigned to the Text property of the label.

The next two highlighted methods are event handlers for the Application_Start and Application_End events, exactly the same as seen in the previous example , GlobalEvents . These event handlers call the method WriteFile , listed further down in the class file. The public accessibility modifier has been added to the WriteFile method declaration, changing it from the default accessibility of private . This makes the method available to the entire application.

WriteFile is not static . That is, it requires an instance of the class to be invoked. The following two lines of code in a web page code-behind file get a reference to an instance of the class, then invoke WriteFile :

 GlobalMembers g = new GlobalMembers(  );     g.WriteFile("Instance method - Now in Page_Load of web page."); 

Example 18-7 also demonstrates a static version of WriteFile , called StaticWriteFile . It is made static by the use of the static keyword. It can be invoked directly without first instantiating the class, similar to the static variable:

 GlobalMembers.StaticWriteFile("Static method - Now in Page_Load of web page."); 

In this example, there is no real reason to use the static instead of the instance methods, since the method content itself is identical. In the general case, however, instance methods are required when the method needs to refer to the specific instance of the class. Suppose the global method is working with a DataSet or some other object specific to this invocation of the page; then an instance global method would be called for. Otherwise, a static global method can be used.



Programming ASP. NET
Programming ASP.NET 3.5
ISBN: 0596529562
EAN: 2147483647
Year: 2003
Pages: 173

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net