671

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;
    }
}
JohnB
  • 18,046
  • 16
  • 98
  • 110
Aen
  • 7,433
  • 3
  • 20
  • 21

4 Answers4

760

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.

stil
  • 5,306
  • 3
  • 38
  • 44
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • 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. – Aliostad Nov 21 '12 at 16:41
  • 25
    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)`). – Stephen Cleary Nov 21 '12 at 17:15
  • 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. – Aen Nov 28 '12 at 02:08
  • 77
    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. :) – NathanAldenSr May 08 '14 at 19:36
  • 29
    @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. – Stephen Cleary May 08 '14 at 20:32
  • @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.... – Royi Namir May 10 '14 at 08:46
  • 3
    @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). – Stephen Cleary May 11 '14 at 01:13
  • 1
    @StephenCleary,so does this means that in webapi controller we should not use ConfigureAwait(false)? – Anshul Nigam May 27 '14 at 09:18
  • 6
    @AnshulNigam: You should use `ConfigureAwait(false)` whenever you don't need the request context. – Stephen Cleary May 27 '14 at 12:28
  • 2
    @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) – Anshul Nigam May 28 '14 at 09:21
  • 11
    @AnshulNigam: Which is why controller actions need their context. But most methods that the actions call do not. – Stephen Cleary May 28 '14 at 10:53
  • 1
    @StephenCleary, isn't it worth mentioning your other points on deadlocks? http://stackoverflow.com/questions/13140523/await-vs-task-wait-deadlock?rq=1 – Jonathan Roeder Sep 09 '14 at 18:30
  • 15
    @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. – Stephen Cleary Sep 09 '14 at 18:57
  • @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? – Eric J. Oct 13 '15 at 19:15
  • @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. – Stephen Cleary Oct 13 '15 at 19:34
  • @StephenCleary I didn't want to ask it here in the comments: http://stackoverflow.com/questions/33711136/thread-returning-to-thread-pool-when-using-await – user4205580 Nov 14 '15 at 18:12
  • @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. – Stephen Cleary Nov 14 '15 at 19:04
  • 1
    @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 Aug 18 '16 at 15:42
  • This is an example http://resharper-plugins.jetbrains.com/packages/ConfigureAwaitChecker – neleus Aug 18 '16 at 15:47
  • @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. – Alexander Derck Aug 30 '16 at 13:02
  • 3
    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*. – Stephen Cleary Aug 30 '16 at 13:15
  • @StephenCleary Oh misinterpreted your comment, my bad. Thanks for clearing it up – Alexander Derck Aug 30 '16 at 13:20
  • @StephenCleary any thoughts on what neleus suggested as an alternate workaround? – eglasius Jan 12 '17 at 12:29
  • @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. – Stephen Cleary Jan 12 '17 at 14:14
  • 1
    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? – eglasius Jan 12 '17 at 14:29
  • @eglasius: The best way to avoid a deadlock is to not block on async code at all. – Stephen Cleary Jan 12 '17 at 15:16
  • 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. – eglasius Jan 12 '17 at 15:35
  • I had the same issue with my ASP.NET webform app.[My Question](http://stackoverflow.com/questions/41934142/make-webmethod-async-webform) 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 – JB's Feb 02 '17 at 05:56
  • @MuhammadIqbal: I don't know if `WebMethod` supports `async`. I've never used asmx. (Note: `WebMethod` is asmx, not WebForms). – Stephen Cleary Feb 02 '17 at 14:01
  • 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> 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. – JB's Feb 02 '17 at 17:19
  • 3
    @MuhammadIqbal: My recommendation would be to move from asmx to WebAPI. – Stephen Cleary Feb 02 '17 at 18:05
  • 1
    @StephenCleary please update this post to include content from your recent post http://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html – JJS May 31 '17 at 14:13
  • 2
    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 – Mick Jun 22 '17 at 02:55
  • @StephenCleary what about `Xamarin`? it's same as `ASP.NET Core` in this case? – Mehdi Dehghani Feb 25 '19 at 06:32
  • @MehdiDehghani: No. UI frameworks including Xamarin have a synchronization context, and code must be in that context to access UI elements. – Stephen Cleary Feb 25 '19 at 21:37
  • 1
    the whole topic is so vague and misleading. even @stephen – JBoothUA Jul 02 '19 at 00:58
  • 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 Jul 02 '19 at 00:59
  • Your first sentence "If you are on ASP.NET Core, it does not matter whether you use ConfigureAwait(false) or not" doesn't hold true. Check this article (https://devblogs.microsoft.com/dotnet/configureawait-faq/): Whereas the classic ASP.NET on .NET FW has its own SynchronizationContext, in contrast ASP.NET Core does not. That means that code running in an Core app won’t see a custom SynchronizationContext, which lessens the need for ConfigureAwait(false) running in such an environment. It doesn’t mean, however, that there will never be a custom SynchronizationContext or TaskScheduler present. – Luis Gouveia Sep 17 '21 at 16:59
  • @LuisGouveia: Yes, if you are using a custom `SynchronizationContext` or `TaskScheduler`, then `ConfigureAwait(false)` will allow you to avoid it. But by default, there is no such thing on ASP.NET Core, and if *you add it*, then you *will also know* whether you need to avoid it. FWIW, I don't know of *anyone* who has used a custom SyncCtx or TaskSched on ASP.NET Core. – Stephen Cleary Sep 17 '21 at 18:35
  • @StephenCleary, I shouldn't have written "your sentence doesn't hold true". Instead I should have written that "your sentence only applies to applications that don't use external dependencies or applications where you're 100% sure the dependencies don't use custom sync contexts". I think that could be added (after discussing it with a colleague of mine). – Luis Gouveia Sep 20 '21 at 07:37
  • Careful people. not all of ASP.NET Core `"does not have synchronization context"`!! SignalR, for example, does have one, so you will get deadlocks without `ConfigureAwait(false)` – Alex from Jitbit Oct 07 '21 at 16:32
  • Nice answer Stephen. Btw the video link doesn't work anymore. – chaosifier Jul 18 '23 at 09:47
150

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

starball
  • 20,030
  • 7
  • 43
  • 238
tugberk
  • 57,477
  • 67
  • 243
  • 335
  • 2
    "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. – casperOne Nov 21 '12 at 15:15
  • 2
    @casperOne I have intended to say the same. – tugberk Nov 21 '12 at 16:53
  • 8
    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? – binki Dec 30 '14 at 03:43
  • 1
    @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. – ToolmakerSteve Sep 21 '15 at 19:27
  • 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. – Keith Robertson Sep 06 '16 at 19:20
  • 1
    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.. – Michael Parker Oct 07 '16 at 15:36
  • @MichaelParker you need it on every call that you awai at the library level. – tugberk Oct 10 '16 at 09:15
  • 4
    Why should the author of a library coddle the consumer? If the consumer wants to deadlock, why should I prevent them? – Quark Soup Jul 25 '18 at 15:56
  • @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. – masterwok Mar 22 '19 at 13: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. – Filip Cordas Apr 24 '19 at 21:46
  • @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. – tugberk Apr 25 '19 at 21:42
  • @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. – Filip Cordas Apr 27 '19 at 00:01
  • @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: https://github.com/tugberkugurlu/Bloggy/blob/3e7d15eeddb075cf4873f0a33eb5954bd75864eb/src/Bloggy.Client.Web/Controllers/ArchiveController.cs#L51-L55 – tugberk Apr 28 '19 at 17:22
  • 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: https://github.com/ravendb/ravendb/pull/545 – tugberk Apr 28 '19 at 17:24
  • @FilipCordas So, my advice to you is that try to understand the context next time before making further judgement calls. – tugberk Apr 28 '19 at 17:24
  • @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 Apr 29 '19 at 20:23
  • 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. – Filip Cordas Apr 29 '19 at 20:28
  • @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. – tugberk May 01 '19 at 14:35
  • 1
    @Sergey.quixoticaxis.Ivanov you forgot to quote the first part of that sentence: "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)" – tugberk Apr 08 '20 at 13:51
36

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

Mick
  • 6,527
  • 4
  • 52
  • 67
14

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.

Ben Collins
  • 20,538
  • 18
  • 127
  • 187
Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • 6
    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 Nov 21 '12 at 13:48
  • 6
    3) You're confusing two different types of "context". The "context" mentioned in C# via CLR is always flowed, even in `Task`s; the "context" controlled by `ContinueWith` is a `SynchronizationContext` or `TaskScheduler`. These different contexts [are explained in detail on Stephen Toub's blog](http://blogs.msdn.com/b/pfxteam/archive/2012/06/15/executioncontext-vs-synchronizationcontext.aspx). – Stephen Cleary Nov 21 '12 at 13:49
  • 21
    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. – Stephen Cleary Nov 21 '12 at 13:49
  • 1
    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 `Thread`s, but doesn't anymore with `ContinueWith()`), this makes your answer confusing to read. – svick Nov 21 '12 at 21:45
  • 1
    @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 Nov 22 '12 at 09:05
  • 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 Nov 22 '12 at 09:08
  • @StephenCleary thanks for the link. Perhaps maybe I was confusing them :) – Aliostad Nov 22 '12 at 09:16
  • 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. – osexpert Dec 27 '18 at 23:48
  • 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. – enorl76 Jan 03 '19 at 02:00