Anda di halaman 1dari 4

Troubleshooting ASP.NET applications with the use of static keywords http://support.microsoft.

com/kb/893666

Article ID: 893666 - Last Review: March 27, 2007 - Revision: 1.4
Troubleshooting ASP.NET applications with the use of static keywords
ASP.NET Support Voice column

Troubleshooting ASP.NET applications with the use of static keywords

To customize this column to your needs, we want to invite you to submit your ideas about topics that interest you and
issues that you want to see addressed in future Knowledge Base articles and Support Voice columns. You can submit your
ideas and feedback using the Ask For It (http://support.microsoft.com /com mon/survey.aspx?scid=sw;en;1176&p0=&p1=&p2=&p3=&p4=)
form. There's also a link to the form at the bottom of this column. Welcome to the
Microsoft ASP.NET Support Voice column! My name is Jerry Orman. I have been with Microsoft over 5 years, and have spent
most of my time focused on Web-related technologies such as Microsoft FrontPage and the new Microsoft SharePoint
technologies. I have spent the last year working with Microsoft ASP.NET as a support engineer. This month in the Support
Voice column, I am going to describe troubleshooting ASP.NET applications with the use of static keywords.

Statics
This article discusses two different behaviors that are caused by static keywords and that can be difficult to troubleshoot.
Hopefully after you read this article, you can avoid these behaviors in your applications and be able to better diagnose them
if they occur.

Users see incorrect data


One symptom that is very difficult to troubleshoot occurs when a user submits data, but another user's information is
displayed or is entered into a database. This behavior typically occurs because of incorrect use of static variables in classes.
A static object is instantiated one time for each application domain, and all processing in the application shares the same
object. For example, let's say you set up a static property in a class by using the following code.

using System; namespace statics { public class BadClass { private static string _MyData; public static string MyData
{ get{return _MyData;} set{_MyData = value;} } } }

The MyData property is static and public. You can access it anywhere in your application by using the following syntax:

BadClass.MyData

So now imagine that you have a page that sets the value of MyData, and then does some work with it. If multiple users hit
the page at the same time, you now have a race condition where the last user who updated MyData wins. The following
sample shows this behavior by setting the static object during a button_click event. This sample also makes the thread
sleep for 15 seconds. This allows both requests to run at the same time. To do this, follow these steps:

1. Create an .aspx Web form.


2. Add a label, a button, and a text box. The HTML will look similar to the following.

<body> <form id="Form1" method="post" runat="server"> <asp:Label id="Label1" runat="server"></asp:Label> <br>


<asp:Button id="Button1" runat="server" Text="Button"></asp:Button> </br> <asp:TextBox id="TextBox1"
runat="server"></asp:TextBox> </form> </body>

3. Double-click the button to create a button_click event.

private void Button1_Click(object sender, System.EventArgs e) { //Set the static property to the value of the
text box. BadClass.MyData = TextBox1.Text; //Make the thread wait 30 seconds
System.Threading.Thread.Sleep(30000); //Set the label to the value of the property. Label1.Text =
BadClass.MyData; }

4. Open two separate Microsoft Internet Explorer processes:


a. Click Start, point to All Programs, and then click Internet Explorer.
b. Repeat step a.
This will ensure that you have two separate Iexplore.exe processes running at the same time. You can check Task
Manager to make sure. When you have two Iexplore.exe processes running at the same time, you have unique
sessions for each page request. Requests that have the same session ID are processed in the order that they come in

1 of 4 9/21/2010 5:26 PM
Troubleshooting ASP.NET applications with the use of static keywords http://support.microsoft.com/kb/893666

and do not run at the same time.


5. Browse your .aspx page in both browser windows.
6. Submit User1 in the text box of one browser window, and then submit User2 in the text box in the other browser
window.

After the pages complete, you will see User2 in both labels.

As mentioned previously, both pages are running at the same time. The first request sets the static property to User1, and
then goes to sleep. While the thread is paused, another request comes in and sets the same object to User2. The thread
that is processing the first request completes, and then displays the value. The value is set to User2.

Avoid this behavior


The best way to avoid this behavior is to not make the object static and to use an instance of the class to set and to retrieve
the values. The property is no longer shared because a copy of the object is created for each request, and you will not see
this behavior. To avoid this behavior, follow these steps:

1. Remove the static modifier from the BadClass.cs file.

using System; namespace statics { public class BadClass { private string _MyData; //Removed static public
string MyData //Removed static { get{return _MyData;} set{_MyData = value;} } } }

2. Change the button_click event.

private void Button1_Click(object sender, System.EventArgs e) { //Create an instance of BadClass BadClass _bad
= new BadClass(); //Set the MyData property on this instance _bad.MyData = TextBox1.Text; //Sleep for 30
seconds System.Threading.Thread.Sleep(30000); //Set the label to the value of the property Label1.Text =
_bad.MyData; }

If you have to use the static object, you have to implement locking when you are using the static object. This prevents both
threads from accessing the object at the same time. To do this, follow these steps:

1. Add a static object to your code behind the page. This object will be a shared resource that the pages can obtain a
lock on.

static object StaticLocker = new object();

2. Change the button_click event to the following.

private void Button1_Click(object sender, System.EventArgs e) { //Lock the object to prevent multiple threads
from writing to the static property lock(StaticLocker) { //Set the static property BadClass.MyData =
TextBox1.Text; //Put the thread to sleep for 30 seconds System.Threading.Thread.Sleep(30000); //Set the label
to the value of the static property Label1.Text = BadClass.MyData; } }

NullReferenceException caused by statics


Another behavior that occurs when you use statics is a System.NullReferenceException exception. For example, you change
your button_click event code to the following.

private void Button1_Click(object sender, System.EventArgs e) { BadClass.MyData = TextBox1.Text;


System.Threading.Thread.Sleep(10000); Label1.Text = BadClass.MyData.ToString(); BadClass.MyData = null; }

If you perform the same test as before, when BadClass.MyData.ToString() is called for the second request, it will throw a
System.NullReferenceException exception. The System.NullReferenceException exception occurs because the first request
set the value to null while the second request was waiting. The resolution for this behavior is the same as for a static
property.

Memory leak caused by static events

If you set up a static event and then subscribe to that event from an .aspx page, the process will eventually run out of

2 of 4 9/21/2010 5:26 PM
Troubleshooting ASP.NET applications with the use of static keywords http://support.microsoft.com/kb/893666

memory. Let's consider you add the following to the BadClass.cs file.

public delegate void MyEvent(); public static event MyEvent BadEvent;

You then wire up the event delegate in the InitializeComponent method of the .aspx page to a method in the page.

private void InitializeComponent() { //Add this with the other items (for example, this.Load). BadClass.BadEvent +=
new BadClass.MyEvent(this.TestEvent); }

You also add the following method to your page. This is the method that you specified when hooking up the event in the
InitializeComponent method:

private void TestEvent() { //Do some work here. }

Why this causes a memory leak

Because the event is static and never goes out of scope, you are adding the method to the list of events that are fired when
the event occurs each time the page is run. The end result of this is that whatever object you wire to the static event is
rooted in memory, and it will never be collected. In this case, that object is the actual .aspx page class.

This behavior occurs in the Windbg.exe debugger or the Cdb.exe debugger by running the !gcroot command on the object
that you are adding the event from. You will see output that is similar to the following.

HANDLE(Strong):c3d11d8:Root:0x90b8838(System.Object[])->0x5346f68(statics.BadClass/MyEvent)->
0x10ff928(statics.BadClass/MyEvent)-> 0x10faa24(statics.BadClass/MyEvent)->

Many object requests have been made to the following events.

0x10e6fe0(statics.BadClass/MyEvent)-> 0x533baf0(ASP.StaticsTest_aspx)

You can see that the bottom item is the .aspx page class, and it is rooted to multiple MyEvent delegates. Because the .aspx
page is rooted, it cannot be cleaned up. The other side effect is that whatever the .aspx page is using also cannot be
cleaned up because they are rooted in the page object.

For more information about the Microsoft .NET garbage collector, visit the following MSDN Web
sites: http://msdn.microsoft.com/msdnmag/issues/1100/GCI/default.aspx (http://msdn.microsoft.com/msdnmag/issues
/1100/GCI/default.aspx) http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/default.aspx
(http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/default.aspx) For more information about the !gcroot command and
obtaining this output, see the ".NET CLR Memory Counters" section of the following MSDN Web site:
http://msdn2.microsoft.com/en-us/library/ms972959.aspx (http://msdn2.microsoft.com/en-us/library/ms972959.aspx)

Avoid this behavior


To avoid this behavior, you can either not use the static keyword on the event or remove the event handler from the page
when you are done using it. In an ASP.NET example, you wire the event when Page_Init is called. You must remove it
when the page unloads by adding an event handler for the Page_Unload event.

Add the following to the InitializeComponents method.

this.Unload += new System.EventHandler(this.Page_Unload); Add the following method to the page to remove the event:
private void Page_Unload(object sender, System.EventArgs e) { BadClass.test -= new BadClass.MyEvent(this.TestEvent);
}

For more information about events, visit the following MSDN Web site: http://msdn2.microsoft.com/en-us/library
/aa645739(vs.71).aspx (http://msdn2.microsoft.com/en-us/library/aa645739(vs.71).aspx) As
always, feel free to submit ideas on topics you want addressed in future columns or in the Knowledge Base using the Ask
For It (http://support.microsoft.com/common/survey.aspx?scid=sw;en;1176&p0=&p1=&p2=&p3=&p4=) form.

APPLIES TO

3 of 4 9/21/2010 5:26 PM
Troubleshooting ASP.NET applications with the use of static keywords http://support.microsoft.com/kb/893666

Microsoft ASP.NET 1.0


Microsoft ASP.NET 1.1

Keywords: kbhowto kbasp KB893666

Get Help Now


Contact a support professional by E-mail, Online, or Phone

Microsoft Support
©2010 Microsoft

4 of 4 9/21/2010 5:26 PM

Anda mungkin juga menyukai