Warning
DotAwait is still in early development. Use with caution!
DotAwait lets you use await in a fluent / LINQ-friendly style via an .Await() extension call.
While await often breaks fluent chains:
var names = (await service.GetUsersAsync())
.Where(u => u.IsActive)
.Select(u => u.Name)
.ToArray();with DotAwait, you can keep the chain intact:
var names = service
.GetUsersAsync()
.Await()
.Where(u => u.IsActive)
.Select(u => u.Name)
.ToArray();Install the DotAwait NuGet package into your project via NuGet Package Manager or the .NET CLI:
dotnet add package DotAwaitDotAwait integrates via MSBuild:
- Content files contains
.Await()extension methods marked with[DotAwait]attribute - A source-rewriting task runs before the
CoreCompiletarget - Calls like
task.Await()becomeawait task - All the methods marked with
[DotAwait]attribute are removed from the rewritten sources - Rewritten sources are emitted under
obj/.../.dotawait/src - Compilation uses rewritten sources instead of original ones
DotAwait is designed to be safe and not cause unexpected runtime errors. The rewrite step is all-or-nothing - if anything goes wrong, the build fails at compile time, not at runtime.
How:
- All
.Await()extension methods are implemented as partial methods with no body - For design-time builds DotAwait adds
DOTAWAIT_DESIGN_TIMEsymbol that enables auto-generated stub implementations of these methods
So:
- In the IDE,
.Await()is available and type-checks correctly - In a normal build,
.Await()is rewritten intoawaitand the partial method definitions are removed - If rewriting fails, the build fails because partial methods have no body
DotAwait provides implicit usings enabled by default to simplify usage.
Implicit usings are a C# 10+ feature, so they may cause issues in projects using older language versions.
To disable DotAwait implicit usings, add the following to your project file:
<PropertyGroup>
<DotAwaitImplicitUsings>disable</DotAwaitImplicitUsings>
</PropertyGroup>DotAwait supports custom awaitable types.
To make your type compatible, you should create an extension method marked with [DotAwait] attribute with single parameter of your awaitable type.
The recommended implementation looks like this (you only need the overloads you actually use):
namespace DotAwait
{
internal static partial class DotAwaitTaskExtensions
{
[DotAwait]
public static partial T Await<T>(this MyTaskType<T> task);
[DotAwait]
public static partial void Await(this MyTaskType task);
}
}- Automated tests
- Code cleanup
- Rewriter optimizations
- Edge-case validation
- Ensure
.props/.targetsdo not affect transitive dependencies - Fix debugger line mapping issues
- Visual Studio extension to highlight
.Await()similarly to theawaitkeyword
This project is licensed under the MIT License