There are four things working together to cause the behavior you are asking about:
- HttpContext is an instance object whose reference can be found in
HttpContext.Current
- Thread is also an instance object whose reference can be found in
Thread.CurrentThread
Thread.CurrentThread
is static but references a different Thread
object in every thread
HttpContext.Current
actually points to Thread.CurrentThread.ExecutionContext.IllogicalCallContext.HostContext
Conclusions we can draw from the above givens:
- Because
HttpContext
is an instance object and not static we need its reference to access it
- Because
HttpContext.Current
actually points to a property on Thread.CurrentThread
, changing Thread.CurrentThread
to a different object will likely change HttpContext.Current
- 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:
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.
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()
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…