4

I have implemented some work which adds values to the Session state inside a Thread. I would like these values to be available outside the Thread (obviously).

The information added to the Session is available outside of the Session without any issues when the Session State mode is "InProc".

When the Session State mode is to "StateServer" however, the behaviour is different. Basically the values set inside the Thread are persisted sometimes and sometimes not. It seems random to me.

Here is code that reproduces the problem.

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    protected void store_Click(object sender, EventArgs e)
    {
        // Set the session values to default.
        Session["Test1"] = "No";
        Session["Test2"] = "No";

        // Set the Test1 session value in the thread.
        ThreadObject threadObject = new ThreadObject() { Username = Page.User.Identity.Name, SessionState = Session };
        worker = new Thread(new ParameterizedThreadStart(Work));
        worker.Start(threadObject);

        // Set the Test2 session value in this thread just to compare.
        Session["Test2"] = "Yes";
    }

    protected void print_Click(object sender, EventArgs e)
    {
        // Print out the Session values.
        label1.Text = string.Empty;
        label1.Text += "Inside Thread: " + Session["Test1"] + ",  \n";
        label1.Text += "Outside: " + Session["Test2"] + "\n";
    }

    private static Thread worker;

    public static void Work(object threadObject)
    {
        // Retrieve the Session object and set the Test2 value.
        ThreadObject threadObject1 = (ThreadObject)threadObject;
        HttpSessionState currentSession = threadObject1.SessionState;
        currentSession["Test1"] = "Yes";
    }
}

public class ThreadObject
{
    public string Username { get; set; }
    public HttpSessionState SessionState { get; set; }
}

The above code works fine with SessionState mode="InProc", but is random with:

<sessionState mode="StateServer"
  stateConnectionString="tcpip=localhost:42424"
  cookieless="false"
  timeout="20"/>

Any ideas?

EDIT: So as per the comments below the thread needs to finish before the Request (Main Thread) finishes, otherwise anything added to the Session is lost. This is because at the end of the Main Thread the Session is serialized and sent to the data store (Out of Process, or SQL Server).

Ivan
  • 43
  • 6

1 Answers1

1

I think this is a timing issue - there's no guarantee that your worker thread will have executed by the time you get to setting your label's values. It takes a few MS to create and launch the tread. By then, the rest of your main thread has probably completed. You can test this by putting debug output and seeing the order in which your code is executed.

If you need to guarantee that the code in your thread executes (which eliminates the need for a thread) - you could use a WaitOne() threading method to have your main thread wait for the worker thread to return. But depending on a value set in a thread to be available in a parallel process is risky.

Additionally - IMHO, I wouldn't use threads in ASP.NET apps - I believe the consensus is that they're a bit dangerous. I've seen app pool crashes because of bad code inside a spawned thread.

Ripside
  • 145
  • 2
  • 8
  • I think you're right with the _race condition_, but threading can be important for ASP.NET, too. There's nothing evil, if implemented and used correctly. Letting the ASP.NET Main-Thread wait on anything will make the thread available to process other requests - That's the reason MVC allows Task. – TGlatzer Feb 25 '13 at 05:45
  • I can't disagree - even though your caveat - "if implemented correctly" seems to be a common problem :-) – Ripside Feb 25 '13 at 05:48
  • Hey, well the label setting code is part of a button click, and I waited more than a few seconds before attempting to print out the session values into the label. So I'm not so sure that it is a timing issue. Pressing the print_Click button repeatedly should eventually allow the Thread to set its value into the session.. – Ivan Feb 25 '13 at 05:55
  • Are you watching your debug output? Any HTTP Exception errors? The main thread could be ending before your worker thread finishes, so the value never gets set. Consistently, anyway. Like I suggested, put some debug output (System.Diagnostics.Debug.WriteLine("output str"); or Trace.WriteLine in each method and see what's getting run and when - although I don't think debug output isn't guaranteed to be in order either in multi-threaded situations. – Ripside Feb 25 '13 at 05:58
  • I was able to reproduce this. Does this StackOverflow question help? It suggests checking if you have web gardens enabled (and to disable them if so). http://stackoverflow.com/questions/2147578/asp-net-session-state-and-multiple-worker-processes – Ripside Feb 25 '13 at 06:37
  • So, you might be right @Ripside that it is a timing issue of some sort. I tried using a Thread delegate instead of a proper thread to run the code and I don't get the problem anymore: ThreadPool.QueueUserWorkItem(delegate(object state) { HttpSessionState s = state as HttpSessionState; s["Test1"] = "Yes"; }, Session); Hmm I still don't know what is going on, but there must be something in the internals about how the ASP queues or locks the Session state and sets its values. Any ideas would be good, but for now I'm happy :) – Ivan Feb 25 '13 at 21:44
  • Are you running this locally in VS only, or on a server? Things might be a little different on a server. I'm curious, in case I run into this myself. – Ripside Feb 25 '13 at 23:24
  • 1
    Ok I think I know what is going on. It seems that at the end of the Page Request the Session is serialized to the ServerState or SQLServer and sent off. So, if the background thread hasn't put its values into the Session by that time then those values are lost. The ship has sailed, the plane has taken off :P I tested this by adding a Thread.Sleep(2000) to my main thread, and now the values are always present, because the background thread has time to do its thing. This is not a very well documented attribute of the StateServer Session mode :) – Ivan Feb 26 '13 at 00:15
  • I agree, that sounds like what's going on. Threading in ASP.Net can be a delicate thing. – Ripside Feb 26 '13 at 05:45