By Arash Emami


2012-11-21 08:24:49 8 Comments

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 SomeAsyncFunctionThatGetsCustomer(id).ConfigureAwait(false);

        // now you are on a different thread!  will that cause problems?
        return customer;
    }
}

4 comments

@Stephen Cleary 2012-11-21 13:40:46

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.

@Aliostad 2012-11-21 16:41:06

My answer got deleted so cannot answer you there. But I am not confusing contexts here, I do not know about you. What is meant by context is Thread Storage Area data. The context does not flow in ContinueWith by default - period. TSA data does not get copied - please prove me wrong if you think otherwise You can check this by looking at HttpContext.Current. That is why we go through hoops and hoops to flow that.

@Stephen Cleary 2012-11-21 17:15:47

Thread-local storage isn't flowed by any context. HttpContext.Current is flowed by the ASP.NET SynchronizationContext, which is flowed by default when you await, but it's not flowed by ContinueWith. OTOH, the execution context (including security restrictions) is the context mentioned in CLR via C#, and it is flowed by both ContinueWith and await (even if you use ConfigureAwait(false)).

@Arash Emami 2012-11-28 02:08:08

Thank you Stephen, I marked your post as the answer. I had to read it a few times to get it, but it seems like the only time it would ever be useful to call ConfigureAwait(false) is in a desktop/mobile app, where you make an asynchronous call (like a HttpWebRequest) and would rather do the processing of the result off the UI thread. Otherwise, it is not worth cluttering up the code for any small performance gains made when using ASP.NET.

@NathanAldenSr 2014-05-08 19:36:27

Wouldn't it be great if C# had native language support for ConfigureAwait(false)? Something like 'awaitnc' (await no context). Typing out a separate method call everywhere is pretty annoying. :)

@Stephen Cleary 2014-05-08 20:32:10

@NathanAldenSr: It was discussed quite a bit. The problem with a new keyword is that ConfigureAwait actually only makes sense when you await tasks, whereas await acts on any "awaitable." Other options considered were: Should the default behavior discard context if in a library? Or have a compiler setting for the default context behavior? Both of these were rejected because it's harder to just read the code and tell what it does.

@Royi Namir 2014-05-10 08:46:20

@StephenCleary I don't understand your line : If you disable the context capture using ConfigureAwait(false), then the thread just continues executing the method directly. — Are you saying that the thread is not back in the threadpool , but still waits till the operation is finished , and when it does , it continues the callback ? ( with the same thread)......— Or - Are you talking about that when the async operation finished , another/same thread from threadpool is back to continue the callback , but it's just doesnt enter the execution context....

@Stephen Cleary 2014-05-11 01:13:51

@RoyiNamir: When the async operation finishes, a thread from the thread pool is used to actually complete the task. If you use ConfigureAwait(false), then that same thread resumes executing the async method without entering the request context. (BTW, this is an implementation detail; this behavior is undocumented).

@Anshul Nigam 2014-05-27 09:18:12

@StephenCleary,so does this means that in webapi controller we should not use ConfigureAwait(false)?

@Stephen Cleary 2014-05-27 12:28:59

@AnshulNigam: You should use ConfigureAwait(false) whenever you don't need the request context.

@Anshul Nigam 2014-05-28 09:21:35

@StephenCleary,but is it very unlikely to not to use request context because for every request one need to send response , something like this.Request.CreateResponse(HttpStatusCode.xxx)

@Stephen Cleary 2014-05-28 10:53:47

@AnshulNigam: Which is why controller actions need their context. But most methods that the actions call do not.

@Jonathan Roeder 2014-09-09 18:30:05

@StephenCleary, isn't it worth mentioning your other points on deadlocks? stackoverflow.com/questions/13140523/…

@Stephen Cleary 2014-09-09 18:57:18

@JonathanRoeder: Generally speaking, you shouldn't need ConfigureAwait(false) to avoid a Result/Wait-based deadlock because on ASP.NET you should not be using Result/Wait in the first place.

@Eric J. 2015-10-13 19:15:21

@StephenCleary: Do I understand correctly from your blog A good rule of thumb is to use ConfigureAwait(false) unless you know you do need the context that using ConfigureAwait(false) will give a performance edge because the current context (e.g. ASP.Net context) is not flowed, but leaving ConfigureAwait(false) out should cause no functional impact?

@Stephen Cleary 2015-10-13 19:34:14

@EricJ.: In some cases it can give you better performance. It'll never give you worse performance. There's no functional impact unless someone is using ConfigureAwait(false) as part of a sync-over-async hack.

@user4205580 2015-11-14 18:12:31

@StephenCleary I didn't want to ask it here in the comments: stackoverflow.com/questions/33711136/…

@Stephen Cleary 2015-11-14 19:04:04

@user4205580: You've already got two good answers. The reason it's not behaving as you expect is because your inner "asynchronous" method is actually synchronous (and the compiler explicitly warns you about this). Make it truly asynchronous (e.g., add an await Task.Delay(200);), and you'll see the thread returned to the thread pool and 200ms later a new thread taken from the thread pool to resume the method.

@neleus 2016-08-18 15:42:57

@StephenCleary, As I can see, the root cause is in improper using of Result/Wait, where ConfigureAwait(false) acts as a workaround. So why so many folks suggest to put this workaround everywhere instead of just fixing the cause. For example, using Task.Run(async () => { await ...}).Wait(); will do the trick and this is easier than putting 100 times ConfigureAwait(false) everywhere in library code. Why does no one suggest it?

@neleus 2016-08-18 15:47:57

@Alexander Derck 2016-08-30 13:02:00

@StephenCleary I'm confused about your comments: "You should use ConfigureAwait(false) whenever you don't need the request context.", but earlier you say "HttpContext.Current is flowed by the ASP.NET SynchronizationContext, which is flowed by default when you await". So any method has access to the request context regardless? When I test it, I can always access HttpContext.Request in my methods, no matter if I call ConfigureAwait(false) or not.

@Stephen Cleary 2016-08-30 13:15:41

The "by default" means "unless you use ConfigureAwait(false)". HttpContext.Request is not going through HttpContext.Current; HttpContext.Current is a static property. Also, note that HttpContext is not safe for multithreaded use; if you use ConfigureAwait(false), you can access HttpContext.Request, but you definitely shouldn't.

@Alexander Derck 2016-08-30 13:20:21

@StephenCleary Oh misinterpreted your comment, my bad. Thanks for clearing it up

@eglasius 2017-01-12 12:29:23

@StephenCleary any thoughts on what neleus suggested as an alternate workaround?

@Stephen Cleary 2017-01-12 14:14:45

@eglasius: It only works if the code executed by the Task.Run doesn't depend on the current context (e.g., HttpContext.Current, any ASP.NET APIs - some of which implicitly depend on an ASP.NET context, dependency injection resolution that is scoped to a request, etc). And keep in mind that "works" in this scenario means "wastes a thread". await is still the best solution.

@eglasius 2017-01-12 14:29:08

Yes, but if you are running any async code that needs the context and thus wouldn't have ConfigureAwait(false), then you are hit by the deadlock anyway. Both approaches don't work in that case or am I missing something?

@Stephen Cleary 2017-01-12 15:16:13

@eglasius: The best way to avoid a deadlock is to not block on async code at all.

@eglasius 2017-01-12 15:35:09

I couldn't agree more. After re-reading the whole thread I can see I didn't set the scenario well. What I get now is: the reason to put it everywhere is to avoid unnecessarily restoring the context, which can give you some (small) gain in performance (so no for the deadlocks). Some people use it for deadlocks when calling it from non async code (typically in big code bases upgrade where it is not possible to fully move to async in one go). It is for this later case that I was comparing ConfigureAwait(false) everywhere to a single Task.Run, as it is easy for it to be missed and end up wrong.

@JB's 2017-02-02 05:56:25

I had the same issue with my ASP.NET webform app.My Question states the problem but I can't find any solution. I used ConfigureAwait(false) with every await and it worked but when the application runs for the first time page loads as expected but if we request the page again page never loads again. @StephenCleary can help on this matter will be fruitful. Thanks

@Stephen Cleary 2017-02-02 14:01:16

@MuhammadIqbal: I don't know if WebMethod supports async. I've never used asmx. (Note: WebMethod is asmx, not WebForms).

@JB's 2017-02-02 17:19:04

I have defined WebMethod in my code behind file, every aspx page has tons of WebMethod in its code behind file. [WebMethod] public static async Task<List<XXX>> GetXXX() => await new BusinessLogic().GetXXX().ConfigureAwait(false); @StephenCleary Thak you very much for the input, but as I am in a scenario can you please give me any recommendations.

@Stephen Cleary 2017-02-02 18:05:53

@MuhammadIqbal: My recommendation would be to move from asmx to WebAPI.

@JJS 2017-05-31 14:13:13

@StephenCleary please update this post to include content from your recent post blog.stephencleary.com/2017/03/…

@Mick 2017-06-22 02:55:47

One thing missing from this answer is Globalisation and Culture. Using ConfigureAwait(false) loses the web.config system.web/globalization settings. See my answer below for more details

@Mehdi Dehghani 2019-02-25 06:32:11

@StephenCleary what about Xamarin? it's same as ASP.NET Core in this case?

@Stephen Cleary 2019-02-25 21:37:37

@MehdiDehghani: No. UI frameworks including Xamarin have a synchronization context, and code must be in that context to access UI elements.

@JBoothUA 2019-07-02 00:58:40

the whole topic is so vague and misleading. even @stephen

@JBoothUA 2019-07-02 00:59:40

you all need to step back and realize there are far so many other scenarios that can cause deadlock and this is still a huge issue. @StephenCleary is confident but the entire framework is whack. in .net core or not. shame

@JBoothUA 2019-07-02 01:00:26

this thread should be deleted

@Aliostad 2012-11-21 13:23:29

I have some general thoughts about the implementation of Task:

  1. Task is disposable yet we are not supposed to use using.
  2. ConfigureAwait was introduced in 4.5. Task was introduced in 4.0.
  3. .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.
  4. 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.
  5. [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.

@Stephen Cleary 2012-11-21 13:48:36

1) You can call Task.Dispose if you want; you just don't need to the vast majority of the time. 2) Task was introduced in .NET 4.0 as part of the TPL, which did not need ConfigureAwait; when async was added, they reused the existing Task type instead of inventing a new Future.

@Stephen Cleary 2012-11-21 13:49:02

3) You're confusing two different types of "context". The "context" mentioned in C# via CLR is always flowed, even in Tasks; the "context" controlled by ContinueWith is a SynchronizationContext or TaskScheduler. These different contexts are explained in detail on Stephen Toub's blog.

@Stephen Cleary 2012-11-21 13:49:38

4) The library author doesn't need to care whether its callers need the context flow, because each asynchronous method resumes independently. So if the callers need the context flow, they can flow it, regardless of whether the library author flowed it or not.

@svick 2012-11-21 21:45:18

At first, you seem to be complaining instead of answering the question. And then you're talking about “the context”, except there are several kinds of context in .Net and it's really not clear which one (or ones?) are you talking about. And even if you're not confused yourself (but I think you are, I believe there is no context that used to flow with Threads, but doesn't anymore with ContinueWith()), this makes your answer confusing to read.

@Aliostad 2012-11-22 09:05:42

@StephenCleary yes, lib dev should not need to know, it is down to the client. I thought I made it clear, but my phrasing was not clear.

@Aliostad 2012-11-22 09:08:32

Item 2: do not agree with. async got nothing to do with this you could make a decision to flow or not in the 4.0 all the same.

@Aliostad 2012-11-22 09:16:21

@StephenCleary thanks for the link. Perhaps maybe I was confusing them :)

@osexpert 2018-12-27 23:48:33

One more general thought: ConfigureAwait does not belong where it is today. Imagine you have an async method X which is calling 100+ async methods with await and ConfigureAwait(Y). This is plain stupid. Y is common for the method X, this ConfigureAwait "thing" belong in a method attribute on X.

@enorl76 2019-01-03 02:00:27

They should've invented the Future, and gone with Thenable specs. Promises in javascript are so much easier to deal with. Now as a library developer, all of my async calls are potential deadlocks if I don't pepper MY code with ConfigureAwait(false). All to make your little examples using await and async keywords look nice.

@Mick 2017-06-22 02:49:01

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).

@Stephen Cleary 2017-06-22 12:49:33

Modern versions of .NET (I think since 4.6?) will propagate culture across threads, even if ConfigureAwait(false) is used.

@Mick 2017-06-23 01:15:41

Thanks for the info. We are indeed using .net 4.5.2

@tugberk 2012-11-21 09:01:21

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:

Finally, there is a great short video from Lucian Wischik exactly on this topic: Async library methods should consider using Task.ConfigureAwait(false).

Hope this helps.

@casperOne 2012-11-21 15:15:36

"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." - I'm getting the impression that you're trying to say that Task walks the stack to get the SynchronizationContext, which is wrong. The SynchronizationContext is grabbed before the call to the Task and then the rest of the code is continued on the SynchronizationContext if SynchronizationContext.Current is not null.

@tugberk 2012-11-21 16:53:08

@casperOne I have intended to say the same.

@binki 2014-12-30 03:43:28

Shouldn’t it be the responsibility of the caller to ensure that SynchronizationContext.Current is clear / or that the library is called within a Task.Run() instead of having to write .ConfigureAwait(false) all over the class library?

@ToolmakerSteve 2015-09-21 19:27:19

@binki - on the other hand: (1) presumably a library is used in many applications, so doing effort one-time in the library to make it easier on applications is cost-effective; (2) presumably the library author knows he has written code that has no reason to require continuing on the original context, which he expresses by those .ConfigureAwait(false)s. Perhaps it would be easier for library authors if that were the default behavior, but I would presume that making it a little bit harder to write a library correctly is better than making it a little bit harder to write an app correctly.

@Keith Robertson 2016-09-06 19:20:26

Another way to put it is that ConfigureAwait(false) is not for use in CustomerController.Get() (or high-level application code, including UI event handlers), which, if it starts with a SynchronizationContext almost certainly needs that context later in the method. It is for implementing library code like SomeAsyncFunctionThatGetsCustomer() which does not need the application context.

@Michael Parker 2016-10-07 15:36:59

Is it possible to simply use ConfigureAwait at the top level, or does it literally need to be on every call all the way down the stack? It would suck to forget to do it on one call and then have that deadlock the main thread..

@tugberk 2016-10-10 09:15:41

@MichaelParker you need it on every call that you awai at the library level.

@Quarkly 2018-07-25 15:56:10

Why should the author of a library coddle the consumer? If the consumer wants to deadlock, why should I prevent them?

@masterwok 2019-03-22 13:31:17

@DonaldAirey I'm wondering this same question and I completely agree with you. What have you found that works best for you? I'm currently thinking it would be best to ConfigureAwait(false) at the WebApiController level.

@Filip Cordas 2019-04-24 21:46:31

@masterwok I started looking around for a good answer to this question but from what I can see all the answers are a copy paste of someone's opinion on how to do http calls in wpf applications. Best answer use ConfigureAwait(false) when you need to don't do cargo cutting for no reason.

@tugberk 2019-04-25 21:42:49

@FilipCordas I guess you have never come across a deadlock situation with this? If you read all the answers, you will see that there is a reason behind this, people don't usually write extra code because it's fun.

@Filip Cordas 2019-04-27 00:01:02

@tugberk no never nor should anyone. You should not be trying to do async work in synchronous functions not that hard to avoid nor is it ever unavoidable. It's silly to do something with out a good reason.

@tugberk 2019-04-28 17:22:31

@FilipCordas I don't think you are reading things correctly. At the time when this question was asked, which was in 2012, there were legitimate cases where you HAD TO run async code in a synchronous fashion (e.g. due to ASP.NET MVC limitations on child actions, etc.). Like this one: github.com/tugberkugurlu/Bloggy/blob/…

@tugberk 2019-04-28 17:24:00

As you can see there, I had to use AsyncHelper.RunSync as RavenDb client didn't handle it correctly at the library level, which resulted in this PR: github.com/ravendb/ravendb/pull/545

@tugberk 2019-04-28 17:24:32

@FilipCordas So, my advice to you is that try to understand the context next time before making further judgement calls.

@Filip Cordas 2019-04-29 20:23:11

@tugberk Well AsyncController was there from 2013 so there was no "had to" it was just simpler. My problem is with "you should always use ConfigureAwait(false)" when in most cases you should not be doing it. You should use it if you don't need the SynchronizationContext not always. And if you are writing a library you should be writing tests cases that make sure you library works and performs well not just calling methods because someone put in a blog post.

@Filip Cordas 2019-04-29 20:28:55

Also if you want people to use your library in a sync way provide a sync api don't make it simpler for people to do bad practices.

@tugberk 2019-05-01 14:35:43

@FilipCordas you still don't get the case, child action DIDN'T support async back then. doesn't matter whether you have AsyncController or not.

Related Questions

Sponsored Content

9 Answered Questions

[SOLVED] How to safely call an async method in C# without await

8 Answered Questions

[SOLVED] Why can't I use the 'await' operator within the body of a lock statement?

  • 2011-09-30 15:23:00
  • Kevin
  • 87242 View
  • 315 Score
  • 8 Answer
  • Tags:   c# .net async-await

2 Answered Questions

1 Answered Questions

5 Answered Questions

[SOLVED] An async/await example that causes a deadlock

3 Answered Questions

1 Answered Questions

1 Answered Questions

2 Answered Questions

[SOLVED] ConfigureAwait(false) on Top Level Requests

0 Answered Questions

Async OnCommand of a Button in an ASP.NET Page

Sponsored Content