How to stop forgetting to await an awaitable call

Edit this page | 1 minute read

Now that all those .NET codebases start to get littered with async and await statements, I’m observing another phenomenon: forgetting to await an awaitable member. Not just in the code I deal with in my day job, but a lot of users of Fluent Assertions have been running into this, especially since we introduced “async” versions such as ThrowAsync and NotThrowAsync. You would expect that modern IDEs have become smart enough to help us with that. And indeed, both Visual Studio and Rider do, but only to an extend.

Consider for example the following (contrived) async method:

public class Class
    public async Task AsyncMethod()
        await Task.Run(() =>
            throw new InvalidOperationException();

If you would call this AsyncMethod without using the await keyword, like this…

Class subjectUnderTest = new();

…no exception will be thrown. But fortunately, the compiler will issue warning CS1998:

This async method lacks ‘await’ operators and will run synchronously. Consider using the ‘await’ operator to await non-blocking API calls, or ‘await Task.Run(…)’ to do CPU-bound work on a background thread.

So if you’re like me and always treat warnings as errors, you’ll be fine.

Now consider a unit test that uses Fluent Assertions to assert that the right type exception is thrown:

// Option 1
Func<Task> act2 = async () => await subjectUnderTest.AsyncMethod();

// Option 2
    .Invoking(x => x.AsyncMethod())

Both options are ways to accomplish that, but both forgot to await the ThrowAsync method. The compiler does not help here either, not even Rider. So even though you may think your tests were successful, the assertion never executed.

But I’m happy to report that the .NET community comes to the rescue. Just install the Lindhart.Analyser.MissingAwaitWarning Roslyn analyzer by Morten Hartlev Lindhart through NuGet and get nice and clear warnings on whatever IDE you’re using:

And while you’re at it, also consider AsyncFixer, a set of excellent Roslyn analyzers created by Semih Okur. After installing, it immediatelly told me that this weird AsyncMethod shouldn’t use async/await in the first place. And it’s right about that, obviously…

So what do you think? Did you run into this little mistake yourself? And did you try any other useful Roslyn analyzers? Let me know by commenting below. Oh, and follow me at @ddoomen to get regular updates on my everlasting quest for better solutions.

Leave a Comment