Global.asax and the HttpApplication class

Global.asax and the HttpApplication class

Posted by on 2004年1月24日

The Global class derived from HttpApplication has many uses, including managing application and request state.

The global.asax file setup by Visual Studio.NET gives every web application a Global class derived from HttpApplication. The class contains event handlers such as Application_Start and Session_Start.

There is a tendency to think each web application will have a single instance of Global. Indeed, in most frameworks an object representing the “application” is a singleton – only one exists. Also, we know the ASP.NET runtime calls Application_Start only once when the application starts. All of these clues seem to imply there would be only one instance of a Global object in our application, but these clues are actually misleading.

The ASP.NET runtime maintains a pool of HttpApplication objects. When an incoming request arrives, the runtime takes an HttpApplication object from the pool to pair with the request. The object remains associated with the request, and only that request, until the request processing is complete. When the request is finished the runtime may return the object to the pool, and later pull it out to service another request later – but only one request at a time is associated with an HttpApplication object.

 

Application State versus Request State

The Application object (of type HttpApplicationState) is what we generally think of when we need to store information global to the application. The Application object is a convenient place to store information such as a database connection string.

 

 

private void Page_Load(object sender, System.EventArgs e)
{
    string connectionString = 
         Application["ConnectionString"].ToString();
    . . . . 
}

 

You can also make your own static variables in the HttpApplication class to carry application state. For example, the above information could also be stored like this:

 

public class Global : System.Web.HttpApplication
{
    public static 
       readonly string ConnectionString = "connection information";

    . . .    
}

 

You can access the member from anywhere in your ASP.NET code like so:

 

    
string connectionString = Global.ConnectionString;

 

It is important to make the string a static member (you could also make a static property accessor) if you want the member to be global for the application.

If you instead use member (non-static) variables, you can use these for request state. For instance, the following code will print out the number of milliseconds used to process a request in the output window of the debugger.

 

    
public class Global : System.Web.HttpApplication
{

   protected DateTime beginRequestTime;

    protected void Application_BeginRequest(Object sender, EventArgs e)
    {
        beginRequestTime = DateTime.Now;
    }

    protected void Application_EndRequest(Object sender, EventArgs e)
    {
       string messageFormat = "Elapsed request time (ms) = {0}";
       TimeSpan diffTime = DateTime.Now - beginRequestTime;
       Trace.WriteLine(
                String.Format(
                    messageFormat, diffTime.TotalMilliseconds
                 )
         );                      
    }
    . . . 
}

 

Now, returning to the question of application state. Which is better: storing object references in the Application object, or making static member variables and properties in the Global class? Both approaches have pros and cons.

Keeping global data in static members of the Global class gives you strong typing. Unlike the Application object, you will not need to typecast or convert values. It is the difference between the following two sections:

 

	
DataSet cachedData = (DataSet)Application[“MyDataSet”];
string myString = Application[“MyString”].ToString();

DataSet cachedData = Global.MyDataSet;
string = Global.MyString;

Strong typing gives you cleaner, more robust code. In performance critical situations it can also save the overhead of running conversions. If you are storing value types, such as integers, strong typing avoids the overhead of boxing and unboxing the value into an object (see references). Also, as mentioned in a previous article, the Application object also has some small overhead due to locking. If you initialize your global data only once and never modify or write to the data, you can avoid the locking overhead with static members on the Global class. If you take this approach, I recommend using accessor properties with only get methods to make sure the data is read only.

If you read as well as write static members of the Global class, remember to be thread safe. The Application object already provides thread safety through a course grained reader / writer lock.

The safest place to initialize the global data is during the Application_Start event.Even though there are multiple instances of the Global object around, the runtime only invokes Application_Start on the first instance of Global it creates. An ideal time to initialize request state is during Application_BeginRequest. Request state variables generally do not require thread safety, as each object services only one request at a time.


by K. Scott Allen (scott @ OdeToCode.com)

Additional references:

INFO: Application Instances, Application Events, and Application State in ASP.NET

Working with HttpApplication Instances

HttpApplication Events

FIX: HttpApplication.OnThreadEnter May Fail Under Memory Pressure

Open the Box! Quick!

========================================================

 

The ASP.NET HttpApplication class hides a number of complex concepts in order to simplify the programming model. Some of these simplifications are designed to handle compatibility issues with the classic Microsoft Active Server Pages (ASP) Application object in order to make migration easier. Therefore, it may be important for developers to understand some of the differences, in particular where performance issues are a concern.

 

 

Application Class and Application Instances

An application class is defined in the Global.asax file. The code in Global.asax defines a new class that is derived from System.Web.HttpApplication. Consider the following code in Global.asax, which adds a new object array to the Application object:

 public class Global : System.Web.HttpApplication
       {
        public Global()
           {
		   InitializeComponent();
           }
protected void Application_Start(Object sender, EventArgs e) { this.Application.Add("TestItem",new object[]{"one","two","three"}); }

And here, in the Page_Load event handler of a page in our Application , we will pull it back out:

 



private void Page_Load(object sender, System.EventArgs e)
{
object[] MyStuff=(object[])Page.Application["TestItem"];
for(int i=0;i<MyStuff.Length;i++)
Response.Write(MyStuff[i]+" <br/>");
}

In the absence of a Global.asax file, the base class, HttpApplication, is used as the application class.

The ASP.NET runtime creates as many instances of application classes as needed to process requests simultaneously. For most applications, this number is limited to the number of threads and remains in the range of 1 through 100, depending on the hardware, server load, configuration, and so on. Many requests reuse application instances, and a list of free application instances is kept during periods of reduced load. Application instances are used in a thread-safe manner, that is, one request at a time. This has important implications:

  • You do not have to worry about locking when you access non-static members of the application class.
  • Application code can store request data for each request in non-static members of the application       class (except after the EndRequest event because this event can maintain the request for a long       time).

Because static members of any class, including an application class, are not thread-safe, the user code must provide appropriate locking for access to static members. This applies to any static member that you add to the application class.

Microsoft provides the following guidelines to access the application instance that is associated with the current request:

  • From the Global.asax, use the this (Me in VB.Net) object.
  • From a page, every page includes a strongly-typed ApplicationInstance property (e.g.,        "Page.Application["TestItem"]")
  • From the HttpContext object, use the HttpContext.ApplicationInstance property (which you type as HttpApplication):
HttpApplication ctx=(HttpApplication)HttpContext.Current.ApplicationInstance;
     object[] MyAppStuff=(object[])ctx.Application["TestItem"];
     for(int j=0;j<MyAppStuff.Length;j++)
Response.Write(MyAppStuff[j]+"<BR/>");

Because Application refers to the global application state dictionary in classic ASP, ASP.NET uses ApplicationInstance and not Application as a property name to refer to the application instance that processes the current request.

Application Events

The lifetime of a request (commonly referred to as the "Http pipeline") consists of a series of the application events (and some implicit steps that ASP.NET implements). These events are listed below in the order in which they are executed:

1.                   BeginRequest

2.                   AuthenticateRequest event

3.                   DefaultAuthentication internal event

4.                   AuthorizeRequest event

5.                   ResolveRequestCache event

6.                   Internal step to "map handler" (when compilation takes place, a page instance is created)

7.                   AcquireRequestState event

8.                   PreRequestHandlerExecute event

9.                   Internal step to "execute handler" (when the page code is executed)

10.               PostRequestHandlerExecute event

11.               ReleaseRequestState event

12.               Internal step to filter responsesUpdateRequestCache event

13.               UpdateRequestCache event

14.               EndRequest event

The following items can handle these events:

  • Internal ASP.NET page framework (for example, steps 6, 9, and 12 in the preceding list).
  • HTTP modules that are configured for the application. The default list of HTTP modules is defined in the Machine.config file. Additional custom modules may be specified by the developer in the web.config for the application.
  • Code in Global.asax that is hooked through the Application_[On]EventName method or that is hooked explicitly when you add event handlers for an alternative handler name:

	  protected void Application_OnBeginRequest(Object sender, EventArgs e)
              {
               Response.Write("OnBeginRequest Fired!");
              }

 

           Each event can have synchronous and asynchronous subscribers. Asynchronous subscribers are executed first. Not all events are always executed; the only event that is always executed is EndRequest. As a result, you should perform all after-request cleanup in the EndRequest event: 

 


	  protected void Application_OnEndRequest(Object sender, EventArgs e)
{ Response.Write("OnEndRequest Fired!<br/>"); }

 

 


In most cases, the actual response content is sent to the client after the application instance is finished with the response (which is after EndRequest).

Application_OnStart and Application_OnEnd

ASP.NET introduces the Application_OnStart and Application_OnEnd "events" for compatibility with classic ASP. These handlers are executed only once in the lifetime of an application and not for every application instance. So, if you change non-static members in these methods, you affect only one application instance and not all instances. You can initialize one application instance either in the constructor or by overriding the Init method.

Application_OnStart is a logical equivalent to the class constructor for the application class, but it offers one advantage: the code has access to the HttpContext for the first request to the application.

Application State

Application state is a global dictionary of late-bound objects, which classic ASP introduces to compensate for the absence of global variables in Microsoft Visual Basic Scripting Edition (VBScript). In ASP.NET, you can access application state through one of the following:

  • Application property (which is defined in both HttpApplication and Page classes)
  • HttpContext.Application

ASP.NET includes application state primarily for compatibility with classic ASP so that it is easier to migrate existing applications to ASP.NET. It is recommended that you store data in static members of the application class instead of in the Application object. This increases performance because you can access a static variable faster than you can access an item in the Application dictionary.

To access static application members from pages in Microsoft Visual C# .NET and Microsoft Visual Basic .NET, you must use the ClassName attribute in Global.asax to name your application class. For example, in a "Script Only" global.asax:

<%@ Application Language="C# | VB" ClassName="MyClass" %>

In CodeBehind:

public class Global : System.Web.HttpApplication

{

public static string StaticTest ="This is the original value";
. . .

If a static member is named MyStaticMember in your Global.asax file, you can use MyClass.MyStaticMember to access it from your page.  

The code in the sample Web application for this article writes items to the output stream that illustrate some of these unique properties as they are set or fired from within the global.asax or the Page itself, and will make it easier to examine and / or experiment with the unique Application Object.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值