C# Task ConfigureAwait - c#

Thought I was getting a handle on ConfigureAwait, then I tried an experiment.
My understanding is that ConfigureAwait(false) will only make a difference if there is a synchronization context.
ASP, WPF, etc. should have a context, but console apps and service apps should not.
To see how it works I made a Web API app and included the following method:
// GET api/values/5
public async Task<string> Get (int id)
{
var syncCtx = SynchronizationContext.Current;
int startThreadId = Thread.CurrentThread.ManagedThreadId;
await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(true);
int endThreadId = Thread.CurrentThread.ManagedThreadId;
return "Start Thread ID: " + startThreadId.ToString() +
": End Thread ID: " + endThreadId.ToString();
}
My prediction was that with no ConfigureAwait or ConfigureAwait set to true, I should see the same thread ID before and after the await.
My first few tests showed exactly that with the true set as above.
Later runs of the code started and ended on different thread ids regardless of ConfigureAwait.
I added syncCtx to convince myself I have a context.
The one caveat I have read is that if the task has completed, you won't be guaranteed the same ID. Is that the case here? If so, why is that the case?
Have I set up a naive or flawed test? If so, what would be a proper test?
I started down this path in a console/service app and realized I was not getting the same thread ID. I was adding ConfigureAwait(false) as recommended in most "best practice" write ups I have seen. Since I like to see how things really work, I tried testing the Thread IDs. Seeing them differ led me through a number of searches that resulted in the above code.

Doing ConfigureAwait(true) (or just leaving it off, as it is the default value) does not make it run on the same thread. It tells SynchronizationContext.Current to do a Post or Send with the rest of the continueation. How Post or Send actually runs that code is not defined.
WindowsFormsSynchronizationContext and DispatcherSynchronizationContext (WinForms and WPF's contexts) both will put the continuation on to the queue of messages to be processed by the Message Pump (the UI thread).
On the other hand, AspNetSynchronizationContext (which is what you are running under) just sets some state information up (like setting HttpContext.Current back to its old value), it then queues the work on the next available thread pool thread. There is no "Message Pump" for ASP.NET, it just does all of its work on the thread pool, so there is no point in trying to get the same thread out of the thread pool at a later time, that thread may already been destroyed by the time the continuation happens.
The times you saw the same ID before and after you just got lucky and the same thread got pulled out of the thread pool before and after the continuation.
I highly recommend you read the MSDN magazine article "It's All About the SynchronizationContext", it goes in to detail explaining how the SynchronizationContext works and goes in to a little detail about the 4 types of contexts built in to .NET.

SynchronizationContext != Thread. If you were using something like WPF with its Dispatcher runtime then, yes, its SynchronizationContext happens to be tied to one specific thread. However things like ASP.NET and WCF are not thread affine, they just carry along with them specific ambient context that needs to be restored on whatever thread they begin executing on next. They may be affine to a specific thread pool, but, again, not a specific thread.
This is precisely why the SynchronizationContext abstraction was introduced: it allows different frameworks to decide exactly what affinity means to them and allows the async/await infrastructure to work on top of them in a totally agnostic way.

Related

Proper way to start and fire-and-forget asynchronous calls?

I have an async call (DoAsyncWork()), that I would like to start in a fire-and-forget way, i.e. I'm not interesting in its result and would like the calling thread to continue even before the async method is finished.
What is the proper way to do this? I need this in both, .NET Framework 4.6 as well as .NET Core 2, in case there are differences.
public async Task<MyResult> DoWorkAsync(){...}
public void StarterA(){
Task.Run(() => DoWorkAsync());
}
public void StarterB(){
Task.Run(async () => await DoWorkAsync());
}
Is it one of those two or something different/better?
//edit: Ideally without any extra libraries.
What is the proper way to do this?
First, you need to decide whether you really want fire-and-forget. In my experience, about 90% of people who ask for this actually don't want fire-and-forget; they want a background processing service.
Specifically, fire-and-forget means:
You don't care when the action completes.
You don't care if there are any exceptions when executing the action.
You don't care if the action completes at all.
So the real-world use cases for fire-and-forget are astoundingly small. An action like updating a server-side cache would be OK. Sending emails, generating documents, or anything business related is not OK, because you would (1) want the action to be completed, and (2) get notified if the action had an error.
The vast majority of the time, people don't want fire-and-forget at all; they want a background processing service. The proper way to build one of those is to add a reliable queue (e.g., Azure Queue / Amazon SQS, or even a database), and have an independent background process (e.g., Azure Function / Amazon Lambda / .NET Core BackgroundService / Win32 service) processing that queue. This is essentially what Hangfire provides (using a database for a queue, and running the background process in-proc in the ASP.NET process).
Is it one of those two or something different/better?
In the general case, there's a number of small behavior differences when eliding async and await. It's not something you would want to do "by default".
However, in this specific case - where the async lambda is only calling a single method - eliding async and await is fine.
It depends on what you mean by proper :)
For instance: are you interested in the exceptions being thrown in your "fire and forget" calls? If not, than this is sort of fine. Though what you might need to think about is in what environment the task lives.
For instance, if this is a asp.net application and you do this inside the lifetime of a thread instantiated due to a call to a .aspx or .svc. The Task becomes a background thread of that (foreground)thread. The foreground thread might get cleaned up by the application pool before your "fire and forget" task is completed.
So also think about in which thread your tasks live.
I think this article gives you some useful information on that:
https://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
Also note that if you do not return a value in your Tasks, a task will not return exception info. Source for that is the ref book for microsoft exam 70-483
There is probably a free version of that online somewhere ;P https://www.amazon.com/Exam-Ref-70-483-Programming-C/dp/0735676828
Maybe useful to know is that if your have an async method being called by a non-async and you wish to know its result. You can use .GetAwaiter().GetResult().
Also I think it is important to note the difference between async and multi-threading.
Async is only useful if there are operations that use other parts of a computer that is not the CPU. So things like networking or I/O operations. Using async then tells the system to go ahead and use CPU power somewhere else instead of "blocking" that thread in the CPU for just waiting for a response.
multi-threading is the allocation of operations on different threads in a CPU (for instance, creating a task which creates a background thread of the foreground thread... foreground threads being the threads that make up your application, they are primary, background threads exist linked to foreground threads. If you close the linked foreground thread, the background thread closes as well)
This allows the CPU to work on different tasks at the same time.
Combining these two makes sure the CPU does not get blocked up on just 4 threads if it is a 4 thread CPU. But can open more while it waits for async tasks that are waiting for I/O operations.
I hope this gives your the information needed to do, what ever it is you are doing :)

Understanding context in .Net Task execution

I have been trying to understand the concept of context in Task execution in .Net. However, I still am unable to relate context to basic concept of OS threads. While going through this blog, I sort of got the following idea of what a context is:
In GUI applications, there is a single GUI thread which has all the
GUI elements. Now, because one needs to come in the GUI thread to
access the GUI elements, I am assuming the GUI thread has the GUI
elements initialized in its stack space which it doesn't share with
other threads. Therefore, the awaitable needs to schedule the
remainder of the function in the GUI thread if the remainder function
wants to access some GUI element. Similarly, if we talk about HTTP
application which accept HTTP get/post requests, there is a thread
which gets spawned when a request arrives. This thread contains the request context like IP address of the user. Now, if the remainder
function wants to access some HTTP context properties, it has to execute in that thread.
While reading this blog, I came across the idea of context being copied. This has led to me believe the following:
The context of a thread is data members like IP address, GUI elements
etc. When the remainder of a function is scheduled after an awaitable
completes, the remainder may need the context to be present, but not
necessarily on the same thread. So, what is done is any thread is
taken out of the thread pool and the context is copied onto that
thread so that it is accessible. Thereafter, the remainder function is
scheduled on this thread. This can cause a deadlock in the following way. Take GUI
applications for example. At any time, there should be a unique thread
having the GUI context. So, if the GUI thread blocks and doesn't
release the context, the remainder function won't get scheduled.
Can anyone please clarify this for me? What exactly is in a context? And how is the context transferred? Which of the above understanding of mine is right or both are wrong?
UPDATE:
I read this blog and it has a line And this extension method demonstrates how to invoke a function with a specified ExecutionContext (typically, captured from another thread). This is pushing me to believe that my second idea is closer to correctness.
Each context is different. But in general, they're not copied. Contexts are used to schedule Tasks. That is, to find a suitable thread and other resources, as required, and to then execute the task.
In some contexts (GUI), the most important thing is the thread. There's one UI thread, so any Task that a GUI context is asked to schedule has to arrange for the UI thread to execute that Task.
In some contexts (ASP.Net before core), what's important are the "ambient" request/response/session objects. Those objects should only be accessed by a single thread at a time, but any thread can be used. So the context can use thread pool threads but needs to ensure it only executes a single Task at a time.
And in the default context, there's no special thread nor any other special resources. Like the ASP.Net context above, any thread pool thread can be used to execute the Task but it can schedule Tasks as quickly as the thread pool will take them.

Deadlock when accessing StackExchange.Redis

I'm running into a deadlock situation when calling StackExchange.Redis.
I don't know exactly what is going on, which is very frustrating, and I would appreciate any input that could help resolve or workaround this problem.
In case you have this problem too and don't want to read all this;
I suggest that you'll try setting PreserveAsyncOrder to false.
ConnectionMultiplexer connection = ...;
connection.PreserveAsyncOrder = false;
Doing so will probably resolve the kind of deadlock that this Q&A is about and could also improve performance.
Our setup
The code is run as either a Console application or as an Azure Worker Role.
It exposes a REST api using HttpMessageHandler so the entry point is async.
Some parts of the code have thread affinity (is owned by, and must be run by, a single thread).
Some parts of the code is async-only.
We are doing the sync-over-async and async-over-sync anti-patterns. (mixing await and Wait()/Result).
We're only using async methods when accessing Redis.
We're using StackExchange.Redis 1.0.450 for .NET 4.5.
Deadlock
When the application/service is started it runs normally for a while then all of a sudden (almost) all incoming requests stop functioning, they never produce a response. All those requests are deadlocked waiting for a call to Redis to complete.
Interestingly, once the deadlock occur, any call to Redis will hang but only if those calls are made from an incoming API request, which are run on the thread pool.
We are also making calls to Redis from low priority background threads, and these calls continue to function even after the deadlock occurred.
It seems as if a deadlock will only occur when calling into Redis on a thread pool thread. I no longer think this is due to the fact that those calls are made on a thread pool thread. Rather, it seems like any async Redis call without continuation, or with a sync safe continuation, will continue to work even after the deadlock situation has occurred. (See What I think happens below)
Related
StackExchange.Redis Deadlocking
Deadlock caused by mixing await and Task.Result (sync-over-async, like we do). But our code is run without synchronization context so that doesn't apply here, right?
How to safely mix sync and async code?
Yes, we shouldn't be doing that. But we do, and we'll have to continue doing so for a while. Lots of code that needs to be migrated into the async world.
Again, we don't have a synchronization context, so this should not be causing deadlocks, right?
Setting ConfigureAwait(false) before any await has no effect on this.
Timeout exception after async commands and Task.WhenAny awaits in StackExchange.Redis
This is the thread hijacking problem. What's the current situation on this? Could this be the problem here?
StackExchange.Redis async call hangs
From Marc's answer:
...mixing Wait and await is not a good idea. In addition to deadlocks, this is "sync over async" - an anti-pattern.
But he also says:
SE.Redis bypasses sync-context internally (normal for library code), so it shouldn't have the deadlock
So, from my understanding StackExchange.Redis should be agnostic to whether we're using the sync-over-async anti-pattern. It's just not recommended as it could be the cause of deadlocks in other code.
In this case, however, as far as I can tell, the deadlock is really inside StackExchange.Redis. Please correct me if I'm wrong.
Debug findings
I've found that the deadlock seems to have its source in ProcessAsyncCompletionQueue on line 124 of CompletionManager.cs.
Snippet of that code:
while (Interlocked.CompareExchange(ref activeAsyncWorkerThread, currentThread, 0) != 0)
{
// if we don't win the lock, check whether there is still work; if there is we
// need to retry to prevent a nasty race condition
lock(asyncCompletionQueue)
{
if (asyncCompletionQueue.Count == 0) return; // another thread drained it; can exit
}
Thread.Sleep(1);
}
I've found that during the deadlock; activeAsyncWorkerThread is one of our threads that is waiting for a Redis call to complete. (our thread = a thread pool thread running our code). So the loop above is deemed to continue forever.
Without knowing the details, this sure feels wrong; StackExchange.Redis is waiting for a thread that it thinks is the active async worker thread while it is in fact a thread that is quite the opposite of that.
I wonder if this is due to the thread hijacking problem (which I don't fully understand)?
What to do?
The main two question I'm trying to figure out:
Could mixing await and Wait()/Result be the cause of deadlocks even when running without synchronization context?
Are we running into a bug/limitation in StackExchange.Redis?
A possible fix?
From my debug findings it seems as the problem is that:
next.TryComplete(true);
...on line 162 in CompletionManager.cs could under some circumstances let the current thread (which is the active async worker thread) wander off and start processing other code, possibly causing a deadlock.
Without knowing the details and just thinking about this "fact", then it would seem logical to temporarily release the active async worker thread during the TryComplete invocation.
I guess that something like this could work:
// release the "active thread lock" while invoking the completion action
Interlocked.CompareExchange(ref activeAsyncWorkerThread, 0, currentThread);
try
{
next.TryComplete(true);
Interlocked.Increment(ref completedAsync);
}
finally
{
// try to re-take the "active thread lock" again
if (Interlocked.CompareExchange(ref activeAsyncWorkerThread, currentThread, 0) != 0)
{
break; // someone else took over
}
}
I guess my best hope is that Marc Gravell would read this and provide some feedback :-)
No synchronization context = The default synchronization context
I've written above that our code does not use a synchronization context. This is only partially true: The code is run as either a Console application or as an Azure Worker Role. In these environments SynchronizationContext.Current is null, which is why I wrote that we're running without synchronization context.
However, after reading It's All About the SynchronizationContext I've learned that this is not really the case:
By convention, if a thread’s current SynchronizationContext is null, then it implicitly has a default SynchronizationContext.
The default synchronization context should not be the cause of deadlocks though, as UI-based (WinForms, WPF) synchronization context could - because it does not imply thread affinity.
What I think happens
When a message is completed its completion source is checked for whether it is considered sync safe. If it is, the completion action is executed inline and everything is fine.
If it is not, the idea is to execute the completion action on a newly allocated thread pool thread. This too works just fine when ConnectionMultiplexer.PreserveAsyncOrder is false.
However, when ConnectionMultiplexer.PreserveAsyncOrder is true (the default value), then those thread pool threads will serialize their work using a completion queue and by ensuring that at most one of them is the active async worker thread at any time.
When a thread becomes the active async worker thread it will continue to be that until it have drained the completion queue.
The problem is that the completion action is not sync safe (from above), still it is executed on a thread that must not be blocked as that will prevent other non sync safe messages from being completed.
Notice that other messages that are being completed with a completion action that is sync safe will continue to work just fine, even though the active async worker thread is blocked.
My suggested "fix" (above) would not cause a deadlock in this way, it would however mess with the notion of preserving async completion order.
So maybe the conclusion to make here is that it is not safe to mix await with Result/Wait() when PreserveAsyncOrder is true, no matter whether we are running without synchronization context?
(At least until we can use .NET 4.6 and the new TaskCreationOptions.RunContinuationsAsynchronously, I suppose)
These are the workarounds I've found to this deadlock problem:
Workaround #1
By default StackExchange.Redis will ensure that commands are completed in the same order that result messages are received. This could cause a deadlock as described in this question.
Disable that behavior by setting PreserveAsyncOrder to false.
ConnectionMultiplexer connection = ...;
connection.PreserveAsyncOrder = false;
This will avoid deadlocks and could also improve performance.
I encourage anyone that run into to deadlock problems to try this workaround, since it's so clean and simple.
You'll loose the guarantee that async continuations are invoked in the same order as the underlying Redis operations are completed. However, I don't really see why that is something you would rely on.
Workaround #2
The deadlock occur when the active async worker thread in StackExchange.Redis completes a command and when the completion task is executed inline.
One can prevent a task from being executed inline by using a custom TaskScheduler and ensure that TryExecuteTaskInline returns false.
public class MyScheduler : TaskScheduler
{
public override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return false; // Never allow inlining.
}
// TODO: Rest of TaskScheduler implementation goes here...
}
Implementing a good task scheduler may be a complex task. There are, however, existing implementations in the ParallelExtensionExtras library (NuGet package) that you can use or draw inspiration from.
If your task scheduler would use its own threads (not from the thread pool), then it might be a good idea to allow inlining unless the current thread is from the thread pool. This will work because the active async worker thread in StackExchange.Redis is always a thread pool thread.
public override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// Don't allow inlining on a thread pool thread.
return !Thread.CurrentThread.IsThreadPoolThread && this.TryExecuteTask(task);
}
Another idea would be to attach your scheduler to all of its threads, using thread-local storage.
private static ThreadLocal<TaskScheduler> __attachedScheduler
= new ThreadLocal<TaskScheduler>();
Ensure that this field is assigned when the thread starts running and cleared as it completes:
private void ThreadProc()
{
// Attach scheduler to thread
__attachedScheduler.Value = this;
try
{
// TODO: Actual thread proc goes here...
}
finally
{
// Detach scheduler from thread
__attachedScheduler.Value = null;
}
}
Then you can allow inlining of tasks as long as its done on a thread that is "owned" by the custom scheduler:
public override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// Allow inlining on our own threads.
return __attachedScheduler.Value == this && this.TryExecuteTask(task);
}
I am guessing a lot based on the detailed information above and not knowing the source code you have in place. It sounds like you may be hitting some internal, and configurable, limits in .Net. You shouldn't be hitting those, so my guess is that you are not disposing of objects since they are floating between threads which won't allow you to use a using statement to cleanly handle their object lifetimes.
This details the limitations on HTTP requests. Similar to the old WCF issue when you didn't dispose of the connection and then all WCF connections would fail.
Max number of concurrent HttpWebRequests
This is more of a debugging aid, since I doubt you really are using all the TCP ports, but good info on how to find how many open ports you have and to where.
https://msdn.microsoft.com/en-us/library/aa560610(v=bts.20).aspx

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.

Best practice to call ConfigureAwait for all server-side code

When you have server-side code (i.e. some ApiController) and your functions are asynchronous - so they return Task<SomeObject> - is it considered best practice that any time you await functions that you call ConfigureAwait(false)?
I had read that it is more performant since it doesn't have to switch thread contexts back to the original thread context. However, with ASP.NET Web Api, if your request is coming in on one thread, and you await some function and call ConfigureAwait(false) that could potentially put you on a different thread when you are returning the final result of your ApiController function.
I've typed up an example of what I am talking about below:
public class CustomerController : ApiController
{
public async Task<Customer> Get(int id)
{
// you are on a particular thread here
var customer = await GetCustomerAsync(id).ConfigureAwait(false);
// now you are on a different thread! will that cause problems?
return customer;
}
}
Update: ASP.NET Core does not have a SynchronizationContext. If you are on ASP.NET Core, it does not matter whether you use ConfigureAwait(false) or not.
For ASP.NET "Full" or "Classic" or whatever, the rest of this answer still applies.
Original post (for non-Core ASP.NET):
This video by the ASP.NET team has the best information on using async on ASP.NET.
I had read that it is more performant since it doesn't have to switch thread contexts back to the original thread context.
This is true with UI applications, where there is only one UI thread that you have to "sync" back to.
In ASP.NET, the situation is a bit more complex. When an async method resumes execution, it grabs a thread from the ASP.NET thread pool. If you disable the context capture using ConfigureAwait(false), then the thread just continues executing the method directly. If you do not disable the context capture, then the thread will re-enter the request context and then continue to execute the method.
So ConfigureAwait(false) does not save you a thread jump in ASP.NET; it does save you the re-entering of the request context, but this is normally very fast. ConfigureAwait(false) could be useful if you're trying to do a small amount of parallel processing of a request, but really TPL is a better fit for most of those scenarios.
However, with ASP.NET Web Api, if your request is coming in on one thread, and you await some function and call ConfigureAwait(false) that could potentially put you on a different thread when you are returning the final result of your ApiController function.
Actually, just doing an await can do that. Once your async method hits an await, the method is blocked but the thread returns to the thread pool. When the method is ready to continue, any thread is snatched from the thread pool and used to resume the method.
The only difference ConfigureAwait makes in ASP.NET is whether that thread enters the request context when resuming the method.
I have more background information in my MSDN article on SynchronizationContext and my async intro blog post.
Brief answer to your question: No. You shouldn't call ConfigureAwait(false) at the application level like that.
TL;DR version of the long answer: If you are writing a library where you don't know your consumer and don't need a synchronization context (which you shouldn't in a library I believe), you should always use ConfigureAwait(false). Otherwise, the consumers of your library may face deadlocks by consuming your asynchronous methods in a blocking fashion. This depends on the situation.
Here is a bit more detailed explanation on the importance of ConfigureAwait method (a quote from my blog post):
When you are awaiting on a method with await keyword, compiler
generates bunch of code in behalf of you. One of the purposes of this
action is to handle synchronization with the UI (or main) thread. The key
component of this feature is the SynchronizationContext.Current which
gets the synchronization context for the current thread.
SynchronizationContext.Current is populated depending on the
environment you are in. The GetAwaiter method of Task looks up for
SynchronizationContext.Current. If current synchronization context is
not null, the continuation that gets passed to that awaiter will get
posted back to that synchronization context.
When consuming a method, which uses the new asynchronous language
features, in a blocking fashion, you will end up with a deadlock if
you have an available SynchronizationContext. When you are consuming
such methods in a blocking fashion (waiting on the Task with Wait
method or taking the result directly from the Result property of the
Task), you will block the main thread at the same time. When
eventually the Task completes inside that method in the threadpool, it
is going to invoke the continuation to post back to the main thread
because SynchronizationContext.Current is available and captured. But
there is a problem here: the UI thread is blocked and you have a
deadlock!
Also, here are two great articles for you which are exactly for your question:
The Perfect Recipe to Shoot Yourself in The Foot - Ending up with a Deadlock Using the C# 5.0 Asynchronous Language Features
Asynchronous .NET Client Libraries for Your HTTP API and Awareness of async/await's Bad Effects
Finally, there is a great short video from Lucian Wischik exactly on this topic: Async library methods should consider using Task.ConfigureAwait(false).
The biggest draw back I've found with using ConfigureAwait(false) is that the thread culture is reverted to the system default. If you've configured a culture e.g ...
<system.web>
<globalization culture="en-AU" uiCulture="en-AU" />
...
and you're hosting on a server whose culture is set to en-US, then you will find before ConfigureAwait(false) is called CultureInfo.CurrentCulture will return en-AU and after you will get en-US.
i.e.
// CultureInfo.CurrentCulture ~ {en-AU}
await xxxx.ConfigureAwait(false);
// CultureInfo.CurrentCulture ~ {en-US}
If your application is doing anything which requires culture specific formatting of data, then you'll need to be mindful of this when using ConfigureAwait(false).
I have some general thoughts about the implementation of Task:
Task is disposable yet we are not supposed to use using.
ConfigureAwait was introduced in 4.5. Task was introduced in 4.0.
.NET Threads always used to flow the context (see C# via CLR book) but in the default implementation of Task.ContinueWith they do not b/c it was realised context switch is expensive and it is turned off by default.
The problem is a library developer should not care whether its clients need context flow or not hence it should not decide whether flow the context or not.
[Added later] The fact that there is no authoritative answer and proper reference and we keep fighting on this means someone has not done their job right.
I have got a few posts on the subject but my take - in addition to Tugberk's nice answer - is that you should turn all APIs asynchronous and ideally flow the context . Since you are doing async, you can simply use continuations instead of waiting so no deadlock will be cause since no wait is done in the library and you keep the flowing so the context is preserved (such as HttpContext).
Problem is when a library exposes a synchronous API but uses another asynchronous API - hence you need to use Wait()/Result in your code.

Categories