Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The cross-thread usage of "HttpContext.Current" property and related things

I read from < Essential ASP.NET with Examples in C# > the following statement:

Another useful property to know about is the static Current property of the HttpContext class. This property always points to the current instance of the HttpContext class for the request being serviced. This can be convenient if you are writing helper classes that will be used from pages or other pipeline classes and may need to access the context for whatever reason. By using the static Current property to retrieve the context, you can avoid passing a reference to it to helper classes. For example, the class shown in Listing 4-1 uses the Current property of the context to access the QueryString and print something to the current response buffer. Note that for this static property to be correctly initialized, the caller must be executing on the original request thread, so if you have spawned additional threads to perform work during a request, you must take care to provide access to the context class yourself.

I am wondering about the root cause of the bold part, and one thing leads to another, here is my thoughts:

We know that a process can have multiple threads. Each of these threads have their own stacks, respectively. These threads also have access to a shared memory area, the heap.

The stack then, as I understand it, is kind of where all the context for that thread is stored. For a thread to access something in the heap it must use a pointer, and the pointer is stored on its stack.

So when we make some cross-thread calls, we must make sure that all the necessary context info is passed from the caller thread's stack to the callee thread's stack.

But I am not quite sure if I made any mistake.

Any comments will be deeply appreciated.

Thanks.

ADD

Here the stack is limited to user stack.

like image 302
smwikipedia Avatar asked Nov 13 '11 04:11

smwikipedia


People also ask

Is HttpContext current items thread safe?

The HttpContext is NOT thread safe, accessing it from multiple threads can result in exceptions, data corruption and generally unpredictable results.

What is the use of HttpContext?

The HttpContext encapsulates all the HTTP-specific information about a single HTTP request. When an HTTP request arrives at the server, the server processes the request and builds an HttpContext object. This object represents the request which your application code can use to create the response.

How use HttpContext current in .NET core?

Current property, instead it is available in the HttpContext class in ASP.Net Core applications. Session can be enabled using the Configure method. Inside this method, you will have to call the UseSession method of the app object. Note: It is mandatory to call the UseSession method before the UseMvc method.

How do I find HttpContext current?

If you're writing custom middleware for the ASP.NET Core pipeline, the current request's HttpContext is passed into your Invoke method automatically: public Task Invoke(HttpContext context) { // Do something with the current HTTP context... }


2 Answers

There are four things working together to cause the behavior you are asking about:

  1. HttpContext is an instance object whose reference can be found in HttpContext.Current
  2. Thread is also an instance object whose reference can be found in Thread.CurrentThread
  3. Thread.CurrentThread is static but references a different Thread object in every thread
  4. HttpContext.Current actually points to Thread.CurrentThread.ExecutionContext.IllogicalCallContext.HostContext

Conclusions we can draw from the above givens:

  1. Because HttpContext is an instance object and not static we need its reference to access it
  2. Because HttpContext.Current actually points to a property on Thread.CurrentThread, changing Thread.CurrentThread to a different object will likely change HttpContext.Current
  3. Because Thread.CurrentThread' changes when switching threads, HttpContext.Current also changes when switching threads (in this case HttpContext.Current becomes null).

Bringing this all together, what causes HttpContext.Current to not work in a new Thread? The Thread.CurrentThread reference change, which happens when switching threads, changes the HttpContext.Current reference, which prevents us from getting to the HttpContext instance we want.

To reiterate, the only magic thing going on here is Thread.CurrentThread referencing a different object in every Thread. HttpContext works just like any other instance object. Since threads in the same AppDomain can reference the same objects, all we have to do is pass a reference for HttpContext to our new thread. There is no context info to load or anything like that. (there are some fairly serious potential gotchas with passing around HttpContext to other threads but nothing to prevent you from doing it).

A few final side notes I came across while researching:

  1. In some cases a Thread's ExecutionContext is 'flowed' (copied) from one Thread to another. Why then is HttpContext not 'flowed' to our new Thread? Because HttpContext doesn't implement the ILogicalThreadAffinative interface. A class stored in the ExecutionContext is only flowed if it implements ILogicalThreadAffinative.

  2. How does ASP.NET move HttpContext from Thread to Thread (Thread-Agility) if it isn't flowed? I'm not entirely sure, but it looks like it might pass it in HttpApplication.OnThreadEnter().

like image 152
Mark Rucker Avatar answered Oct 05 '22 09:10

Mark Rucker


I think I've found a suitable explanation here: http://odetocode.com/articles/112.aspx

To summarize, the code-behind of HttpContext.Current looks like this:

public static HttpContext get_Current() {      return (CallContext.GetData("HtCt") as HttpContext);  } 

with CallContext functioning as thread-local storage (i.e. each thread will see a different copy of the data and cannot access the copies seen by other threads). Hence, once the current context is initialized on one thread, subsequent accesses by other threads will result in a NullReferenceException, since the property is thread-local to the initial thread.

So yes, your initial explanation was close, in the sense that it is a problem of data being visible only to a single thread.

like image 42
Tudor Avatar answered Oct 05 '22 08:10

Tudor