When working with the .NET session state you should bear in mind that the HttpContext.Current.Session cannot be transferred to another thread. Imagine that you, from the Global.asax would like to read the SessionID each time a session is started:
// This method inside Global.asax is called for every session start protected void Session_Start(object sender, EventArgs e) { MyClass.DoSomethingWithTheSession(HttpContext.Current); }
To speed up performance you wish to use a thread inside DoSomethingWithTheSession. The thread will read the Session ID:
public class MyClass { public static void DoSomethingWithTheSession(HttpContext context) { if (context == null) return; // Here the context is not null ThreadPool.QueueUserWorkItem(DoSomethingWithTheSessionAsync, context); } private static void DoSomethingWithTheSessionAsync(object httpContext) { HttpContext context = (HttpContext)httpContext; // Oops! Here the context is NULL string sessionID = context.Session.SessionID; } }
The code above will fail because the HttpContext is not thread safe. So in DoSomethingWithTheSession(), the context is set, but in DoSomethingWithTheSessionAsync, the context will null.
THE SOLUTION: TRANSFER THE SESSION VALUES INSTEAD OF THE SESSION OBJECT:
To make it work, rewrite the DoSomethingWithTheSessionAsync() method to reteieve the values needed, not the HttpContext object itself:
public class MyClass { public static void DoSomethingWithTheSession(HttpContext context) { if (context == null) return; // Transfer the sessionID instead of the HttpContext and everything is fine ThreadPool.QueueUserWorkItem(DoSomethingWithTheSessionAsync, context.Session.SessionID); } private static void LogReportFeatureflagsAsync(object session) { // This works fine, as the string is thread safe. string sessionID = (string)session; // Do work on the sessionID } }
MORE TO READ:
- Is working with the Session thread-safe? from StackOverflow
- Is Session variable thread-safe within a Parallel.For loop in ASP.Net page from StackOverflow
