2

Update for future readers: If you find this text too long: This is a race condition due to a static variable. What you are reading below is showing how confusing this can become for someone who is debugging it and overlooking the static keyword. If you are experiencing similar behaviour always check for static first.

I am debugging this application, but cannot find a bug in the code. The class of my master page has a private property called Greeting. This property does not cause trouble until two users on the same server log out at about the same time (within less than one second). Then one user gets the greeting that was meant for the other user (for example, if John and Jane were testing, both would see "Dear Misses Jane!"). So, for debugging purposes I implemented a getter and a setter for this property. Both write the value that is read or written to the trace.axd via HttpContext.Current.Trace.Write(). I am seeing that the correct value is set. But in the last get the value of the corresponding other user is read.There are two consecutive calls of the getter that return different values. There is no call to the setter inbetween. The property is private, and code analysis is showing, that it is not referenced from anywhere else. I am also writing the stack trace to the trace with Environment.StackTrace. Code is running as expected. How can this be anything different than an error in .NET itself?

    private static string _Greeting = String.Empty;
    private static string Greeting
    {
        get
        {
            System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__get(): " + _Greeting);
            System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__get() STACKTRACE: " + Environment.StackTrace);
            return _Greeting;
        }
        set
        {
            _Greeting = value;
            System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__set(): " + _Greeting);
            System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__set() STACKTRACE: " + Environment.StackTrace);
        }
    }

Excerpt of the Trace (with pseudonyms):

 Debug  myMasterPage.Greeting__get(): Dear Misses Jane  
 Debug  myMasterPage.Greeting__get(): Dear Mister John
Leif
  • 2,143
  • 2
  • 15
  • 26

4 Answers4

7

The problem is the fact that this variable is static and hence when one user logs in and the value is set, another user logs in and changes it. So you know, a static variable is variable that is shared among all the Threads (Requests) and there are very few cases where you would want to declare a static variable on a web application.

Icarus
  • 63,293
  • 14
  • 100
  • 115
  • I think you are absolutely right. It just hasn't gotten to my mind that this is working across different threads aka requests. Damn, I feel so dumb! Thx. I will check it and quite possibly mark your answer as solution later. – Leif Aug 16 '13 at 14:53
  • +1 @Icarus Technically there are still various reasons to use `static`, but normally they are nearly all connected to the `Singleton` pattern – xanatos Aug 16 '13 at 14:58
  • Ok. Verified noob bug. – Leif Aug 16 '13 at 15:08
1

You have what is known as a race condition

    private static string Greeting
    {
        get
        {
            /*1.*/ Trace.Write("Debug", "myMasterPage.Greeting__get(): " + _Greeting);
            /*2.*/ return _Greeting;
        }
        set
        {
            /*3.*/ _Greeting = value;
            /*4.*/ Trace.Write("Debug", "myMasterPage.Greeting__set(): " + _Greeting);
        }
    }

I've numbered the relevant rows to show how your result can be achieved when two threads (A and B) run through the same code - along the lines of:

 StaticClass.Greeting = "Hi "+username;
 //some other code
 Display(ShowStaticClass.Greeting);
  1. Program starts, _Greeting == string.Empty.
  2. Thread A starts execution, reaches the relevant code. Executes line 3. _Greeting == "A"
  3. Thread A executes line 4. Writes out "_Greeting saved as A"
  4. Thread A executes line 1. Writes out "_Greeting read as A"
  5. Thread B starts execution, reaches the relevant code. Executes line 3. _Greeting == "B"
  6. Thread B executes line 4. Writes out "_Greeting saved as B"
  7. Thread A executes line 2. returns _Greeting == "B"
  8. Thread B executes line 4. Writes out "_Greeting saved as B"
  9. Thread B executes line 1. Writes out "_Greeting read as B"
  10. Thread B executes line 2. returns _Greeting == "B"

This will result in the following log:

"_Greeting saved as A"
"_Greeting read as A"
"_Greeting saved as B"
"_Greeting read as B"

while returning the value "Hi B" for both threads.

Lines 3 and 6 do not execute one after the other, but there can be (and will be) code that executes after the one, and before the other. That way, your debug logging basically lies to you, while telling you nothing but the truth.

SWeko
  • 30,434
  • 10
  • 71
  • 106
0

You should use Session in asp.net page if you want some data be stored for each user if you want to save data in server side , or you could put it in ViewState (on client side)

Bahram
  • 1,464
  • 2
  • 22
  • 38
0

here is a nice post about static variables, it should explain your problem. What is the use of static variable in C#? When to use it? Why can't I declare the static variable inside method?

Community
  • 1
  • 1
Bagzli
  • 6,254
  • 17
  • 80
  • 163