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.
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.
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.
In order 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, then 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.asaxfile is shown in Example 20-1 in VB.NET and in Example 20-2 in C#.
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: est.txt",true); string str; str = DateTime.Now.ToString( ) + " " + strText; writer.WriteLine(str); writer.Close( ); } </script>
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
.
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#
, or JS
for VB.NET, C#, or
JScript .NET, 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 .aspxfile, 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.
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:
<%@ 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 Sytem.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
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
in
directory) are automatically linked to the
application. Therefore, any assembly located in the
in
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:
<%@ Assembly Name="SomeAssembly" %> <%@ Assembly Src="SomeSourceFile.cs" %>
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 sections below. 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.
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 byevent 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: est.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.
The following are all the events fired with every page request, in the order in which they are fired:
Raised for every request handled by ASP.NET. Code in this event handler is executed before the web page or service processes the request.
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.
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.
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.
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.
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.
Raised when the output cache is updated, if the output is to be cached.
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.
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:
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.
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.
Raised for every session that starts. This is a good place to place code that is session-specific.
Raised for every session that ends. This provides an opportunity to save any data stored in session state.
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.
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: est.txt",true); string str; str = DateTime.Now.ToString( ) + " " + strText; writer.WriteLine(str); writer.Close( ); } </script>
In order 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>
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 contain a Response.Write method to indicate that the method 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: est.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
and 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));
and in VB.NET:
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_Loadmethod (in C#):
void Page_Load(Object Source, EventArgs E) { lblMessage.Text = Request.QueryString(Msg); }
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"%>
and in C# it might look like:
<%@ 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:
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 20-5:
In order 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:
<%@ Application Language="VB" ClassName="ProgAspNet"%>
and in C# it will look like:
<%@ Application Language="C#" ClassName="ProgAspNet"%>
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:
public shared successRate as integer = 50
and in C#, it will look like:
public static int successRate = 50;
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:
public void WriteFile(string strText)
and the VB method declaration will look like:
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:
<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
while 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.")
p.WriteFile("Now in Page_Load of web page.");
External source code files can be included in the application using server-sideincludes. 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#:
<!--#IncludePathType
="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 |
---|---|
|
|
|
|
Looking at the sample global.asaxlisted 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.
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.
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.asaxfile. 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.
18.118.24.106