Is HttpApplicationState.RemoveAll() thread safe? - asp.net

In my asp.net application, i want to cache some data in the HttpApplicationState.
My code to set the data looks like this:
Application.Lock();
Application.Set("Name", "Value");
Application.UnLock();
When I read the documentation, it says that HttpApplicationState is implicitly thread safe. But on many blogs it's written that we should use Application.Lock() and Application.Unlock() while writing data to the HttpApplicationState.
On the other hand, I could not find any documentation which says that we should use lock while reading data from HttpApplicationState or while clearing it (using Application.RemoveAll()) method.
My questions are:
Should not we take care of thread-safety when we are calling RemoveAll? In my application, it's possible that one thread is reading a data from HttpApplicationState whereas other thread could call RemoveAll.
In this case when reading and clearing HttpApplicationState is possible from two different threads at the same time, should reading too not be thread safe?

You only need the lock if you are doing more than one operation against the application state. In you case you are just doing one operation, so it's perfectly safe without the lock:
Application.Set("Name", "Value");
If you do more than one operation, and they rely on each other, you need the lock. For example:
Application.Lock();
string name = Application.Get("Name");
if (name == null) {
Application.Set("Name", "Value");
}
Application.UnLock();

As far as I can tell, the RemoveAll is thread safe as it calls the Clear method internally.
The Clear method calls HttpApplicationStateLock.AcquireWrite and then calls the base.BaseClear and finally releases the lock.
Also have a look at
HttpApplicationState - Why does Race condition exist if it is thread safe?

Related

Awaited async Task loses HttpContext.Current

I have a very bizarre situation regarding a Web Application that makes an asynchronous Http Post...
We have two branches in TFS. I merged code from one branch to another and then find that some Integration Tests in the new branch fail due to a System.NullReferenceException. I spend time ensuring that our code in both branches is identical, and all the referenced DLLs are identical too. Everything seems identical.
So, I decide to debug the test.
What our test does is to create a Mock IHttpClient object. We stub the Mock object in such a way that the clientMock.PostAsyncWithResponseMessage(x,y) returns a new HttpResponseMessage() object (on which we've set various properties).
So, the code looks like this:
using (var response = await client.PostAsyncWithResponseMessage(url, postData).ConfigureAwait(true))
{
if (response.IsSuccessStatusCode)
{
ret.Response = await response.Content.ReadAsStringAsync().ConfigureAwait(true);
ret.ContentType = response.Content.Headers.ContentType.ToString();
}
ret.StatusCode = response.StatusCode.ToInt();
}
Taking this a line at a time:
await client.PostAsyncWithResponseMessage(url, postData).ConfigureAwait(true))
This looks like it's an async method, but "client" is our Mock object so all it is doing is supporting the IHttpClient interface. If you inspect the Thread, the ID does not change when executing this line.
Later on, we have:
await response.Content.ReadAsStringAsync().ConfigureAwait(true);
Now, when this line executes, the HttpContext.Current is set to null - all our context is trashed. In this application, we do not call ConfigureAwait(false) anywhere, so as far as I'm aware there's no reason why we should lose the context.
If I change that line to:
response.Content.ReadAsStringAsync().Result;
Then this is of course blocking and we don't lose the context.
So two questions:
Why would the await method().ConfigureAwait(true) lose the context? [More marks will of course be awarded if one can also suggest why identical code from one TFS branch fails whilst working in a different branch, but I'm not expecting that]
I can see the obvious benefits of awaiting the .PostAsyncWithResponseMessage(url, postData) method since our thread would otherwise be blocked as the other server processed our request. However, having retrieved the data, what advantage is there in awaiting the ReadAsStringAsync()....in other words, is there a good reason not to use the .Result syntax?
thanks
If you inspect the Thread, the ID does not change when executing this line.
This does not necessarily mean that it ran synchronously. Most unit test frameworks provide a free-threaded context (SynchronizationContext.Current is null) and run their tests on a thread pool thread. It is entirely possible for the code to just happen to resume on the same thread (especially if you were only running one test).
Now, when this line executes, the HttpContext.Current is set to null - all our context is trashed. In this application, we do not call ConfigureAwait(false) anywhere, so as far as I'm aware there's no reason why we should lose the context.
I assume SynchronizationContext.Current is set to null, so there isn't actually a context. What's probably happening is that the test is setting HttpContext.Current (on some random thread pool thread), and after the first truly asynchronous operation, sometimes the test resumes on a thread where Current is set and sometimes it doesn't.
On ASP.NET, there's a request context (SynchronizationContext) that handles the propagation of HttpContext.Current. If you don't have something similar in your unit tests, then there's no context to preserve HttpContext.Current.
If you are looking for a quick fix, then you can probably use my AsyncContext type. This will provide a single-threaded context so that all your asynchronous code will resume on the same thread - not the same semantics as ASP.NET's context, but similar enough to be useful for some tests:
void TestMethod()
{
AsyncContext.Run(async () =>
{
// Test method body goes here.
});
}
On a side note, ConfigureAwait(true) is just noise; true is the default behavior.
is there a good reason not to use the .Result syntax?
It's not clear from your code that the server's response is actually read by the time PostAsyncWithResponseMessage completes. Based on the descriptions of your problem (and the fact that Result fixes it in your tests), it sounds like ReadAsStringAsync is in fact acting asynchronously.
If this is the case, then there are two good reasons not to block: 1) You're blocking a thread unnecessarily, and 2) You're opening yourself up to deadlock.

Correct way to use MagicalRecord in a concurrent NSOperation (MagicalRecord-2.3)

With MR_contextForCurrentThread not being safe for Operations (and being deprecated), Im trying to ensure I understand the best pattern for series of read/writes in a concurrent operations.
It's been advised to use saveWithBlock for storing new records, and presumably deletion, which provides a context for use. The Count and fetch methods can be given a context, but still use MR_contextForCurrentThread by default.
Is the safest pattern to obtain a context using [NSManagedObjectContext MR_context] at the start of the operation, and use it for all actions. The operation depends on some async work, but not long running. Then perform a MR_saveToPersistentStoreWithCompletion when the operation is finished?
What's the reason for using an NSOperation? There are two options here:
Use MagicalRecord's background saving blocks:
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
// Do your task for the background thread here
}];
The other option is (as you've already tried) to bundle it up into an NSOperation. Yes, I would cache an instance of a private queue context using [NSManagedObjectContext MR_newContext] (sorry, I deprecated the MR_context method this afternoon in favour of a clearer alternative). Be aware that unless you manually merge changes from other contexts, the private queue context that you create will be a snapshot of the parent context at the point in time that you created it. Generally that's not a problem for short running background tasks.
Managed Object Contexts are really lightweight and cheap to create — whenever you're about to do work on any thread other than the main thread, just initialise and use a new context. It keeps things simple. Personally, I favour the + saveWithBlock: and associated methods — they're just simple.
Hope that helps!
You can't use saveWithBlock from multiple threads (concurrent NSOperations) if you want to:
rely on create by primary attribute feature of Magical Record
rely on automatic establishment of relationships (which relies on primary attribute)
manually fetch/MR_find objects and do save based on result of it
This is because whenever you use saveWithBlock new local context created, so that multiple context created in the same time and they don't know about changes in each other. As Tony mentioned localContext is a snapshot of rootContext and changes goes only in one direction, from localContext to rootContext, but not vice versa.
Here is thread-save (or even consistency-safe in terms of MagicalRecord) method that synchronizes calls to saveWithBlock:
#implementation MagicalRecord (MyActions)
+ (void) my_saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;
{
static dispatch_semaphore_t semaphore;
static dispatch_once_t once;
dispatch_once(&once, ^{
semaphore = dispatch_semaphore_create(1);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[MagicalRecord saveWithBlock:block
completion:^(BOOL success, NSError *error) {
dispatch_semaphore_signal(semaphore);
if (completion){
completion(success, error);
}
}];
});
}
#end

Why is ASP.NET HttpContext.Current not set when starting a task with current synchronization context

I was playing around with asynchronous features of .NET a little bit and came up with a situation that I couldn't really explain. When executing the following code inside a synchronous ASP.NET MVC controller
var t = Task.Factory.StartNew(()=>{
var ctx = System.Web.HttpContext.Current;
//ctx == null here
},
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext()
);
t.Wait();
ctx is null within the delegate. Now to my understanding, the context should be restored when you use the TaskScheduler.FromCurrentSynchronizationContext() task scheduler. So why isn't it here? (I can, btw, see that the delegate gets executed synchronously on the same thread).
Also, from msdn, a TaskScheduler.FromCurrentSynchronizationContext() should behave as follows:
All Task instances queued to the returned scheduler will be executed
through a call to the Post method on that context.
However, when I use this code:
var wh = new AutoResetEvent(false);
SynchronizationContext.Current.Post(s=> {
var ctx = System.Web.HttpContext.Current;
//ctx is set here
wh.Set();
return;
},null);
wh.WaitOne();
The context is actually set.
I know that this example is little bit contrived, but I'd really like to understand what happens to increase my understanding of asynchronous programming on .NET.
Your observations seem to be correct, it is a bit puzzling.
You specify the scheduler as "TaskScheduler.FromCurrentSynchronizationContext()". This associates a new "SynchronizationContextTaskScheduler". Now if you look into this class it uses:
So if the task scheduler has access to the same "Synchronization
Context" and that should reference
"LegacyAspNetSychronizationContext". So surely it appears that
HttpContext.current should not be null.
In the second case, when you use a SychronizationContext (Refer:MSDN Article) the thread's context is shared with the task:
"Another aspect of SynchronizationContext is that every thread has a
“current” context. A thread’s context isn’t necessarily unique; its
context instance may be shared with other threads."
SynchronizationContext.Current is provided by LegacyAspNetSychronizationContext in this case and internally has a reference to HttpApplication.
When the Post method has to invoke registered callback, it calls HttpApplication.OnThreadEnter, which ultimately results in setting of the current thread's context as HttpCurrent.Context:
All the classes referenced here are defined as internal in the framework and is making it a bit difficult to investigate further.
PS: Illustrating that both SynchornizationContext objects in fact point to "LegacyAspNetSynchronizationContext":
I was googling for HTTPContext info some time ago. And I found this:
http://odetocode.com/articles/112.aspx
It's about threading and HTTPContext. There is good explanation:
The CallContext provides a service extremely similar to thread local storage (except CallContext can perform some additional magic during a remoting call). Thread local storage is a concept where each logical thread in an application domain has a unique data slot to keep data specific to itself. Threads do not share the data, and one thread cannot modify the data local to a different thread. ASP.NET, after selecting a thread to execute an incoming request, stores a reference to the current request context in the thread’s local storage. Now, no matter where the thread goes while executing (a business object, a data access object), the context is nearby and easily retrieved.
Knowing the above we can state the following: if, while processing a request, execution moves to a different thread (via QueueUserWorkItem, or an asynchronous delegate, as two examples), HttpContext.Current will not know how to retrieve the current context, and will return null. You might think one way around the problem would be to pass a reference to the worker thread
So you have to create reference to your HTTPContext.Current via some variable and this variable will be adressed from other threads you will create in your code.
Your results are odd - are you sure there's nothing else going on?
Your first example ( with Task ) only works because Task.Wait() can run the task body "inline".
If you put a breakpoint in the task lambda and look at the call stack, you will see that the lambda is being called from inside the Task.Wait() method - there is no concurrency. Since the task is being executed with just normal synchronous method calls, HttpContext.Current must return the same value as it would from anywhere else in your controller method.
Your second example ( with SynchronizationContext.Post ) will deadlock and your lambda will never run.
This is because you are using an AutoResetEvent, which doesn't "know" anything about your Post. The call to WaitOne() will block the thread until the AutoResetEvent is Set. At the same time, the SynchronizationContext is waiting for the thread to be free in order to run the lambda.
Since the thread is blocked in WaitOne, the posted lambda will never execute, which means the AutoResetEvent will never be set, which means the WaitOne will never be satisfied. This is a deadlock.

ASP.NET session object lifetime pessimistic assumption !

I check a session object and if it does exist then call another method which would use that object indirectly. Although the second method would access this object in a few nanoseconds I was thinking of a situation when the object exactly expires between two calls. Does Session object extends its lifetime on every read access from code for preventing such a problem ? If not how to solve the problem ?
If you are going to say why I don't pass the retrieved object from first method to second one, this is because I pass the ASP.NET Page object which carries many other parameters inside it to second method and if I try to pass each of them separately, there would be many parameters while I just pass one Page object now.
Don't worry, this won't happen
If I understand your situation it works sort of this way:
Access a certain page
If session is active it immediately redirects to the second page or executes a certain method on the first page.
Second page/method uses session
You're afraid that session will expire between execution of the first and second method/page.
Basically this is impossible since your session timer was reset when just before the first page starts processing. So if the first page had active session then your second page/method will have it as well (as long as processing finishes before 20 minutes - default session timeout duration).
How is Session processed
Session is processed by means of an HTTP Module that runs on every request and before page starts processing. This explains the behaviour. If you're not familiar with HTTP Modules, then I suggest you read a bit about IHttpModule interface.
It's quite difficult to understand your question, IMHO, but I will try.
From what I understand, you're doing something like:
string helloWorld = string.Empty;
if (this.Session["myObject"] == null)
{
// The object was removed from the session or the session expired.
helloWorld = this.CreateNewMyObject();
}
else
{
// Session still exists.
helloWorld = this.Session["myObject"].ToString(); // <- What if the session expired just now?
}
or
// What if the session existed here...
if (this.Session["myObject"] == null)
{
this.Session["myObject"] = this.CreateNewMyObject();
}
// ... but expired just there?
string helloWorld = this.Session["myObject"].ToString();
I thought that Session object is managed by the same thread as the page request, which would mean that it is safe to check if object exists, than use it without a try/catch.
I were wrong:
For Cache objects you have to be aware of the fact that you’re dealing essentially with an object accessed across multiple threads
Source: ASP.NET Cache and Session State Storage
I were also wrong about not reading to carefully the answer by Robert Koritnik, which, in fact, clearly answers the question.
In fact, you are warned about the fact that an object might be removed during page request. But since Session lifespan relies on page requests, it would mean that you must take in account the removal of session variables only if your request takes longer than the session timeout (see How is Session processed in the answer by Robert Koritnik).
Of course, such situation is very rare. But if in your case, you are pretty sure that the page request can take longer than 20 minutes (default session timeout), than yes, you must take in account that an object may be removed after you've checked if it exists, but before you really use it.
In this situation, you can obviously increment the session timeout, or use try/catch when accessing the session objects. But IMHO, if the page request takes dozens of minutes, you must consider other alternatives, as Windows services, to do the work.
I'm having difficulties understanding what the problem here is but let me try it again referring to thread safety.
Thread safety issue
If this is a thread safety issue, you can always issue a lock when creating a certain session object so other parallel requests won't run into a problem by double creating your object.
if (obj == null)
{
lock (objLock)
{
if (obj == null)
{
obj = GenerateYourObject();
}
}
}
Check lock documentation on MSDN if you've never used it before. And don't forget to check other web resources as well.

HttpApplicationState - Why does Race condition exist if it is thread safe?

I just read an article that describes how HttpApplicationState has AcquireRead() / AcquireWrite() functions to manage concurrent access. It continues to explain, that in some conditions however we need to use an explict Lock() and Unlock() on the Application object to avoid a Race condition.
I am unable to understand why a race condition should exist for Application state if concurrent access is implicitly handled by the object.
Could someone please explain this to me ? Why would I ever need to use Application.Lock() and Application.Unlock() ? Thank You !
The AcquireRead and AcquireWrite methods are in the internal HttpApplicationStateLock class, so you don't use them yourself. They synchronise access, but only for a single read or write. From your code you use the Lock and Unlock methods if you need to synchronise access.
You would typically need to synchonise the access if you are changing something that is not a single read or write, like adding two application items that rely on each other, or first checking if an item exist and then add it:
Application.Lock()
if (Application["info"] == null) {
Application.Add("info", FetchInfoFromDatabase());
}
Application.Unlock();
HttpApplicationState - where the globally access variables those are visible to all the
users who are using the application. So in order to avoid the race condition while changing
the value of the variables. We need some precautionary, thats why we are using
Application.Lock() and after the job done releasing the same variable to others in the
queue using Application.Unlock()
Application.Lock()
Application("VisitorCount") = Convert.ToInt32(Application("VisitorCount")) + 1
Application.UnLock()

Resources