Thread Static, ASP.NET and Async handlers - c#

Please consider these sceanrios:
An async .ashx handler
A async .asmx web-service method
A sync MVC 5 controller action method
I am trying to figure out a way to set "logical thread" specific data that can be accessed consistently during a "logical" http request, i.e. if the data was set on the thread in the "BeginExecute" part of which-ever async handler you would consider, that data is available in the "EndExecute" part of that asnc handler even if ASP.NET executes the "EndExecute" part on a different OS/.Net thread.
Moreover, I am expecting that the data set in the "BeginExecute" part on whatever OS/.Net thread it was on is NOT available on a subsequent http request if the second request is assigned the thread that was earlier assigned to first http request when it was in "BeginExecute" portion but this thread freed up as the first http request went in its async operation (and its possibly still completing its async operation).
I believe the word "logical thread" or "logical thread context" in .Net actually means the same "logical" flow of operation that I have mentioned (and not the underlying OS/.Net thread that keeps getting re-assigned). If you look at it from a workflow perspective, each http request is a new "logical" operation (even if multiple users invoke the same web-service sequentially or in parallel, each request is a new and separte logical operation), and in this meaning, the "logical" operation is one-time and cannot repeat. However the same underlying OS/.Net threads can be mapped to "logical" operations as they arrive based on their availability.
Additionally I want to expose this data as HttpContext.Current sort of static property. To some people this may come as a surprise, but HttpContext.Current does not work correctly if you are using for example async .asmx web-service methods. I am sure I have read content on web which says HttpContext.Current should always return correct HttpContext, but I have seen it as null in EndExecuteMethod of .asmx web-methods. It would be great if somecan can confirm if I am right in making my last statement, but this statement is not the overall question I am trying to ask here.
After reading a good amount of literature (e.g. What is the difference between log4net.ThreadContext and log4net.LogicalThreadContext?, http://msmvps.com/blogs/jon_skeet/archive/2010/11/08/the-importance-of-context-and-a-question-of-explicitness.aspx, http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html and more including MSDN docs), here are my inferences:
ThreadStatic is local to underlying OS/.Net thread and not to the "logical" operation, hence in my example; data set on first http request in "BeginExecute" would be visible in next http request if the second http request gets assigned the same thread as "BeginExecute" for first thread. And this data won't be available in "EndExecute" if it happens to be re-assigned to another thread by .Net (which would happen in vast majority of the cases).
Thread.SetData is even more problematic for my use-case. It needs data slots to be passed in and if I were to pass in a data slot from a return value of Thread.GetNamedDataSlot, the information is available across the app domain; as named data slots are shared between threads.
CallContext.SetData is like ThreadStatic (which means its not shared by app domain but different http requests would see the same data if they get assgined to the same underlying OS/.Net thread). CallContext.SetData provides an additional ability to marshal the context data for RPC calls which is irrelevant to the current question being asked.
Then there's the ThreadLocal class (.Net 4/.Net 4.5). It could have solved one part of my problem it seems, I could have passed it inside stateObject of BeingExecute operation, and extract from the same stateObject parameter of endExecute operation. From this perspective, ThreadLocal seems to be written for .Net's async support. But it won't work when I need to access it like HttpContext.Current as there's no way I can see to preserve the "logical thread static" instance ofit (unless I have said something incorrectly in my previous 3 points).
And finally it seems CallContext.LogicalSetData does what I intend to achive. Using the set of CallContext.LogicalSetData and CallContext.LogicalGetData methods, I should be able to achieve the HttpContext.Current like impact which works correctly for "logical task executions".
Now come the questions:
Is everything I have said above correct. Please correct any and all incorrect claims I have made.
Are there any other options available for thread static kind of feature in .Net that I missed.
Does CallContext.LogicalSetData/LogicalGetData pass on the context data to RPC calls (the msdn page does not mention clearly, http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext.logicalsetdata(v=vs.110).aspx).
Are there any downsides (performance wise or otherwise) of using CallContext.LogicalSetData/LogicalGetData.
This page says something about copy-on-write behavior for LogicalSetData: http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html. In the context of async handlers/async MVC 5 action methods, what's the impact if I save a reference type using logicalsetdata and later change the state of the reference type. What are the repuccursions.
For mutation/logicalsetdata/async, I still can't see what's the problem by mutating the object. When the async method starts, the copy-on-write behavior would trigger a copy of context data the next time logicalsetdata is called. This is a shallow copy, so my reference object is now actually shared by 2 logical contexts and the changes in one context are visible in the other context which is what I would normally expect from a reference type.
A long question with lots of references, but hopefully I did my research well and the answers would benefit other people too.

I am trying to figure out a way to set "logical thread" specific data that can be accessed consistently during a "logical" http request
The only possible options are HttpContext.Current.Items and the logical CallContext.
Moreover, I am expecting that the data set in the "BeginExecute" part on whatever OS/.Net thread it was on is NOT available on a subsequent http request
HttpContext.Current.Items will always be cleared on a new request, but you'll have to clear the logical CallContext data yourself.
HttpContext.Current does not work correctly if you are using for example async .asmx web-service methods.
I find this surprising. I haven't tried it, but it should work - if you are running on .NET 4.5, targeting .NET 4.5 (i.e., have targetFramework set to 4.5 in your web.config), and aren't using async void.
[ThreadStatic], thread-local data slots, (non-logical) CallContext, and ThreadLocal are all thread-specific data, and will not work for asynchronous code.
Is everything I have said above correct. Please correct any and all incorrect claims I have made.
There is really way too much text in your question. Stack Overflow is a Q&A site, not a mentoring site.
Are there any other options available for thread static kind of feature in .Net that I missed.
No.
Does CallContext.LogicalSetData/LogicalGetData pass on the context data to RPC calls
I have no idea. Try it and see.
Are there any downsides (performance wise or otherwise) of using CallContext.LogicalSetData/LogicalGetData.
There's a definite performance hit. The .NET framework is highly optimized for the common case (no logical call context data).
what's the impact if I save a reference type using logicalsetdata and later change the state of the reference type.
The logical CallContext has shallow-copy-on-write behavior. So, any kind of asynchronous fork/join concurrency (i.e., Task.WhenAll) will end up sharing that state. If you use ConfigureAwait(false), you could also end up with race conditions.
To actually solve your problem, I recommend you first look into why HttpContext.Current doesn't work as expected; my guess (without seeing the project) is that targetFramework is set to 4.0 instead of 4.5. HttpContext.Current.Items is the most performant choice if you can get it working.

Related

How HttpContext.Current works on each request in IIS pipeline?

As you know, the HttpContext.Current returns the current context in the application pipeline.
Also this property is static, so logically any changes on that or on its properties should affect the other pipelines.
A static field identifies exactly one storage location. No matter how
many instances of a class are created, there is only ever one copy of
a static field.
More
How IIS handle this to prevent conflict on the other pipelines and every HttpContext.Current be unique on each pipeline?
For example for two users that already logged into the system, the HttpContext.Current.User.Identity.Name gives the username of the user who sent the request to the server.
ASP.NET Pipeline:
Current is the property, not field, so it's a static method actually.
This method can return different instances for different threads, and it really does.
If you're developing multithread web application, keep in mind a few things.
Don't use ThreadStaticAttribute. It works in Windows and console applications, but it may not work in web applications, since a single request can be handled by different threads, if you use async, await, and Task<T>.
Use HttpContext.Current.Items instead of ThreadStaticAttribute. These Items are "static" in each HttpContext.
Use SynchronizationContext if you need important settings of HttpContext (regional settings, logged user, and your own HttpContext.Items) after asynchronous calls (if you're not using await).
The reason why you should be careful is a thread pool. It's quite possible that your asynchronous method starts to run in a first thread, continues in a second, and ends in a third. Since each thread has its own copy of the thread static field, you can get unpredictable different values of the field in different locations of your method. SynchronizationContext allows you to return to the initial thread with correct values of regional settings, HttpContext.Items, etc. The await operator does it work for you, so you shouldn't care about context, if you're using the await (thanks to #StephenCleary for the correction).
Now for the thread-static fields. When ASP.NET gets a HTTP request, it creates the new instance of HttpContext with empty HttpContext.Items collection. At the same time ThreadStatic fields are initialized already by previous HTTP request. Therefore f.e. a Singleton class, based on a thread-static field may not work properly. It's important both in synchronous and asynchronous methods of a web application.
The answer lies in thread-local storage, implemented with ThreadStatic in .NET. The ambient context design pattern is also relevant here.

Is the use of [ThreadStatic] at odds with asynchronous code?

We have a fairly large existing code base for various webservices built on top of ASP.NET and that code makes heavy use of accessing HttpContext.Current.User (wrapped as Client.User) which I'm fairly sure internally uses [ThreadStatic] to give you that ambient scoping.
I'm currently looking into if it's possible that we start to use more asynchronous code in the form of async/await but I'm having a hard time finding how the use of [ThreadStatic] fits into this. Removing the reliance on [ThreadStatic] isn't really possible due to its heavy use.
It's my understanding that when an await is hit, the execution of the code stops there, the call immediately returns and that a continuation is set up to continue the execution when the asynchronous code returns. Meanwhile, the original thread is free to be used for something else, for example to handle another request. So far my understanding of it.
What I can't really find a definitive answer to is whether or not HttpContext.Current.User is guaranteed to be the same before and after the await.
So basically:
HttpContext.Current.User = new MyPrincipal();
var user = HttpContext.Current.User;
await Task.Delay(30000);
// Meanwhile, while we wait for that lots of other requests are being handled,
// possibly by this thread.
Debug.Assert(object.ReferenceEquals(HttpContext.Current.User, user));
Is that Debug.Assert guaranteed to succeed?
If another request was handled by the same thread as the Task.Delay was pending, that request will have set a different HttpContext.Current.User, so is that previous state somehow stored and restored when the continuation is called?
What I can imagine happening is that behind the scenes the [ThreadStatic] state is kept as some sort of dictionary on the thread itself and that when a thread returns to the thread pool after returning on that await that dictionary is kept safe somewhere and set back onto the thread when it executes the continuation (or on a thread, I'm not sure if it's necessarily even the same thread that handles the continuation), probably with an encouraging pat on the butt and a "go get 'em boy!", but that last part might just be my imagination.
Is that somewhat accurate?
UPDATE: I've tried to put together a small test that attempts this. So far it seems to work and the assertion hasn't failed for any out of hundreds of requests. Can anyone verify if the test makes sense?
https://gist.github.com/anonymous/72d0d6f5ac04babab7b6
async/await are thread-agnostic, meaning that they have a convention that can work within multiple different threading systems.
In general ThreadStatic will not work correctly in async/await, except for trivial cases such as UI contexts where await will resume on the UI thread. For ASP.NET, ThreadStatic is not compatible with async.
However, HttpContext.Current is a special case. ASP.NET defines a "request context" (represented by an AspNetSynchronizationContext instance assigned to SynchronizationContext.Current). By default, awaiting a task will capture this synchronization context and use it to resume the method. When the method resumes, it may be on a different thread, but it will have the same request context (including HttpContext.Current as well as other things such as culture and security).
So, HttpContext.Current is preserved, but any of your own ThreadStatic values are not.
I describe how await works with SynchronizationContext in my async intro. If you want more details, check out my SynchronizationContext MSDN article (particularly the last section on the async CTP).
ThreadStatic is not at odds per se with asynchronous code at all. It is often used in that context to improve performance, by giving each thread its own copy of a specific object, eliminating contention.
Of course, it has to be used carefully. And if you have a scenario where you require the same object instance to be used regardless of which thread the code executes in, then ThreadStatic either won't work, or it will require careful handling of the threads to ensure that each flow of execution comes back to the thread where it belongs.
In some async/await scenarios, you are guaranteed that the continuation happens on the same thread as the original await. For example, when you await from within a GUI thread in a Forms or WPF program. But this is not guaranteed by the async/await features in general.
Ultimately, while you can use ThreadStatic with async/await, you still need to make sure you're using it in the way it's meant: to tie a specific value or object to a specific thread. This is great for general-purpose objects where any given flow of execution that might be continued doesn't care which object it actually uses. Or where you're sure the flow of execution remains in a given thread.
But otherwise, no. You don't want to be using ThreadStatic in scenarios where at the same time you need the flow of execution to always use the same object, but you cannot guarantee that the flow of execution will remain on the same thread. (Sorry if that last statement seems obvious…I just want to make sure it's clear).
Assuming the await was called from a async-friendly call stack (async controller / handler) then, yes, the assert is guaranteed to succeed.
The ASP.NET SynchronizationContext will handle making HttpContext available on return threads (unless you use ConfigureAwait(false)). However this does not apply to thread data in general, so prefer HttpContext.Items if you have that type of "request global" state.

Maintain a reference to HttpContext on different thread after request has completed

I've been trying to determine how safe it is to maintain a read-only reference to the HttpContext after a request has completed. Specifically, I'm looking to grab a reference to HttpContext.Current when a request is executing, and then place a reference to the context into an in-memory queue for later evaluation (possibly up to a few seconds later) on a different thread.
Obviously, trying to work with and attempting to write to the context.Response won't work and I'm not particularly interested in that. Instead, I'm interested in reading a few values on the context.Request property and a few other values from the context itself, e.g. context.Timestamp, context.Items, and maybe a few others.
Preliminary tests indicate I can do this, but I'm trying to program intentionally rather than by coincidence. Can anyone point to any documentation (or perhaps a blog post or something from Jon Skeet) that indicates that references can be maintained after the HTTP request is complete?
No, this isn't safe, but it has little to do with threading.
It's HttpContext.Current. That's context as in "context of the current request".
Don't use this after the request is over!
The various IDisposable resources in the context will have been disposed of, so don't use them. Any number of other things that were valid during the request will not be valid because the request is over.
Once you decide what parts of it you need, copy those parts and save them.

Server-side equivalent of HttpContext?

I have a web app that currently uses the current HttpContext to store a LINQ Data Context. The context is persisted for the current request, on a per user basis, per Rick Strahl's blog:
string ocKey = "ocm_" + HttpContext.Current.GetHashCode().ToString("x")
Thread.CurrentContext.ContextID.ToString();
if (!HttpContext.Current.Items.Contains(ocKey))
{
// Get new Data Context and store it in the HTTP Context
}
However, I have some scripts that execute from the global.asax file, that don't have an HttpContext. The HttpContext.Current is NULL, because the server is the one making the "request".
Is there an equivalent object that I can use to store the Data Context? So I don't have to worry about re-creating it, and attaching/detaching objects? I only want to persist the context for the lifetime of my processes.
UPDATED:
I am currently trying to use a static variable in my DAL helper class. on the first call to one of the methods in the class the DataContext is instantiated, and stored in the static variable. At the end of my process, I call another method that calls Dispose on the DataContext, and sets the static variable to NULL.
Can you not just use a static variable specifically for those scripts? That will have the same life-time as the AppDomain. You should probably think carefully about any concurrency concerns, but it sounds like the simplest way to keep a value around.
(I've just checked, and although one instance of HttpApplication can be used to service multiple requests, each one only serves one request at a time - which suggests that multiple instances are created for concurrent request processing. I haven't validated this, but it does sound like it wouldn't be safe to keep it in an instance variable.)
EDIT: Josh's answer suggests that you want this to be per-thread. That sounds slightly odd to me, as unless you've got a lot of these events occurring, you're quite likely to only ever see them execute on different threads, making the whole sharing business pointless. If you really do want that sort of thing, I'd suggest just using an instance variable in the HttpApplication-derived class - for exactly the reason described in the paragraph above :)
Why not use the current HttpContext? The scripts in your global.asax file are all the result of a request coming into the server, so there should be a context associated with that request which you can grab.
I don't understand the need for generating the key based on the hashcode or the thread. There is going to be a separate instance of HttpContext for each request that comes in, and that instance is going to be specific to the thread that is processing the request. Because of that, the key is pretty much worthless when it's based on the instance of HttpContext and the thread.
Also, how do you dispose of the DataContext when you are done? It implements IDisposable for a reason, so I would recommend against a shared instance like this.
UPDATE
In the comments, it indicates that there is a timer that is running that is executing the scripts. Instead of the timer, I would recommend setting up a Scheduled Task which will call a webservice or predetermined page on the site which will perform the task. Then you will always have an HttpContext to work with.
HttpContext.Current is a static method and should be available from anywhere as long as the code is executing within the context of a request.
In your case your not executing within the context of a request, You could look at using Application.Cache but I would caution against holding a DataContext open. I am not very famillar with linq to entities, so I could be wrong, but generally caching data base related items such as connections is bad.
I would also recommend that you consider moving the logic out of your global.asax and to a windows service. This would let you have more control over these tasks, for example you can shut them down seperatley of the web site.
Edit
As JS points out you could use a static variable. You could also define an instance variable marked with ThreadLocal attribute. This will give each thread its own copy of the variable, and can eliminate contention. Since you want each thread to have its own copy anyways.
Is there a reason why these need to be handled the same way as the other DataContexts? It seems to me that if the context is only needed inside the event handling routine, you shouldn't need to keep it around. Especially if it is in Application_Start (as per your comment), I wouldn't bother caching it anywhere -- just use it locally and pass it to the other methods as needed.
Set the DataContext as the state parameter when creating the timer. Based on the info you posted on the comments, it seems to me that your DataContext is more related to the timers than anything else.
Also avoid using the same DataContext for different timers, because you would end up with mixed modifications from the different timers. Also make sure your same timer logic isn't run twice, since it would cause the same i.e. too short period with no control.

CallContext vs ThreadStatic

What are differences between CallContext and ThreadStatic?
I've understood that in an ASP.NET environment data stored in CallContext could be persisted throughout the request until it ends while ThreadStatic may or may not work since the request may switch threads. I've also learned that the HttpContext is internally stored using the CallContext.
In a regular application they both seem to persist throughout the same thread call. When isn't this the case?
Edit: In the comments I learned that the call context is an abstraction over a thread static store. The ASP.NET framework explicitly moves the data from one thread to the next that is to handle one request. Other framework that wants to provide thread agility could do the same to for contextual storage.
Very often a request will use the same thread throughout, but it certainly won't always be the case - ASP.NET exhibits thread agility. There's an old in-depth blog article about the matter from 2005, but as of .NET 4.5 things are rather better.
Items stored as ThreadStatic are available to more than one request. IIS reuses the thread after a request is complete to process subsequent requests, it can even swap a request from one thread to another during processing. ASP.Net clears down the CallContext after each request.

Categories