20.2 Controlling the Application

Now 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 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 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:

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

20.2.2 global.asax

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

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

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

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:

  • Directives

  • Script blocks

  • Server-side includes

  • Object declarations

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 Directives

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

Application

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

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

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="/books/2/655/1/html/2/SomeSourceFile.cs" %>
20.2.2.2 Script blocks

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

Events

Just 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.txt
8/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:

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 19, 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 19.) 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 fulfilled 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 whether or not 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, web.config, or a server-side include file) 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 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                    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 events
figs/pan2_2004.gif

In 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 methods

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 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:

  1. To assign a name to the class compiled from global.asax, modify the Application directive by adding the ClassName attribute. In VB.NET, the Application directive will then look like this:

    <%@ Application  Language="VB" ClassName="ProgAspNet"%>

    In C#, it will look like this:

    <%@ Application  Language="C#" ClassName="ProgAspNet"%>
  2. Define and initialize a static variable named successRate by adding one of the following lines of code to the script block in the global.asax file. In VB.NET, it will look like this:

    public shared successRate as integer = 50

    In C#, it will look like this:

    public static int successRate = 50;
  3. Add the public keyword to the WriteFile method declaration in order to make that method globally available. The C# method declaration will then look like this:

    public void WriteFile(string strText)

    The VB method declaration will look like this:

    Public Sub WriteFile(strText as string)

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:&nbsp;&nbsp;       <asp:Label                    runat="server"/>       <br/>       <asp:Button                    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 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, 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.

Table 20-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 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 declarations

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



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

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