The default behaviour when await-ing a Task is to return to the caller thread. This behaviour was designed in the time of WPF and Silverlight, when building responsive UI was in the spotlight, so the API designers wanted to make client app developer's lives very easy.
But on the server side or in any library code we should be using ConfigureAwait(false)
, meaning the asynchronous continuation can run wherever it wants, it doesn't have to be marshalled back to a specific thread. And .NET Core - so far - is all about server side apps (ASP.NET, Orleans, etc.) and libraries (.NET Standard).
My proposal is to embrace the fact that .NET Core can potentially introduce breaking changes in new versions and change the default behaviour of await-ing Tasks, and make ConfigureAwait(false)
the default behaviour. In the .NET Core world it actually wouldn't break anything and in libraries we should also use it anyway. So it would be just a nice little touch that wouldn't hurt anyone, but benefit a lot.
The second part of my proposal is a potential introduction of an attribute (or even C# keyword) that can be applied to a method or a whole class, so any await-ed call would be configured with ConfigureAwait(true)
inside. It would be useful later when WPF and WinForms apps will be able to run on top of .NET Core 3.0, and these attributes could be applied typically to code-behind and viewmodel classes/methods. This would be still a major simplification compared to having to use the ConfigureAwait(true)
on every single asynchronous call.
In the .NET Core world it actually wouldn't break anything
It would. For example, xunit has its own SynchronizationContext. And anyone can author their own SynchronizationContext/TaskScheduler; if they were using it and expecting by default continuations to be queued back to those, such a change would break them.
and in libraries we should also use it anyway
In most libraries, that's true. But there are explicitly places where it's not.
The second part of my proposal is a potential introduction of an attribute (or even C# keyword) that can be applied to a method or a whole class, so any await-ed call would be configured with ConfigureAwait(true) inside.
This would need to be a request on the language side, e.g.
https://github.com/dotnet/csharplang/issues/645
https://github.com/dotnet/roslyn/issues/7673
I want to add is changing the ConfigureAwait default behavior will be a challenging for anyone writing a netstandard library which will run on net core and full desktop.
@stephentoub is there any action needed from our side here? or can we close this issue?
is there any action needed from our side here? or can we close this issue?
I appreciate the desire for a change here, but I don't think there's any action on this possible right now. I don't think we can or should change the default.
@petroemil feel free to reply back if you have any more questions or anything need to follow up. Thanks for reporting the issue.
You are right, my suggestion might have been going a bit too far, we probably shouldn't just change the default behaviour as it could break things... but it could be made configurable. An attribute that can be applied on method/class/assembly level maybe.
@petroemil You might be interested in https://github.com/dotnet/roslyn/issues/7673.
Edit: never mind, @stephentoub already linked this above.
So, what is default? Documentation does not say
So, what is default? Documentation does not say
When you write await task;
, that is equivalent to writing await task.ConfigureAwait(true);
.
It could be interesting to apply an attribute to a class, something that denotes that configure await false default should be used, instead of true. This attribute could be applied to API classes, utility function classes, etc. The class could still force a ConfigureAwait(true) if needed, but this would be unlikely.
This would save adding the configure await false to all the await calls inside the class.
Most helpful comment
It could be interesting to apply an attribute to a class, something that denotes that configure await false default should be used, instead of true. This attribute could be applied to API classes, utility function classes, etc. The class could still force a ConfigureAwait(true) if needed, but this would be unlikely.
This would save adding the configure await false to all the await calls inside the class.