It is recommended to use 'await' instead of '.Result' when dealing with async code in C# to avoid blocking calls and complex exceptions.
Abstract
This article discusses the differences between using 'await' and '.Result' when dealing with async code in C#. While both methods can be used to get the result out from an async method, using '.Result' is not one of the better options. The article explains why using 'await' is the preferred way, as it allows the runtime to correctly handle the different threads involved and does not block the current thread. Calling '.Result', on the other hand, is a blocking call, which can result in deadlocks and more complex exceptions. The article concludes by recommending the use of 'await' when calling asynchronous methods in C#.
Bullet points
Asynchronous code in C# is a powerful tool that can be a little hard to get your head around.
Using 'await' is the preferred way of dealing with asynchronous code, as it allows the runtime to correctly handle the different threads involved and does not block the current thread.
Calling '.Result' is a blocking call, which can result in deadlocks and more complex exceptions.
Using 'await' allows for better exception handling and provides more detailed information about the exception.
It is recommended to use 'await' instead of '.Result' when calling asynchronous methods in C#.
Why you shouldn’t call .Result when dealing with async code in C#
There are different ways of getting the result out from an async method, but using .Result is not one of the better options.
Asynchronous code in C# is lovely.
By definition, asynchronous code can be a little hard to get your head around, but languages like C# have developed in such a way to make it very easy to control what’s going on.
A quick re-cap of async code in C#
Say you want to make a HTTP request, and return the resulting status code. That’s an asynchronous thing to do, so you might code it up like this:
You can see that the method has an ‘async’ modifier there, which indicates that the method deals with asynchronous code. It’s returning ‘Task’, which represents the asynchronous operation itself. And within the body of the method, the actual asynchronous HTTP call is preceded by ‘await’, meaning that the method cannot continue until that asynchronous operation has completed.
It’s very neat and tidy.
However, if you’re new to using async code, you might find it a little tricky deciding between all the different ways that you can call async code. The main choice that developers find themselves facing is whether to use ‘await’ or call ‘.Result’ to get that value out of that response.
Let’s look at both options.
Why you want to use ‘await’
In the example above, you can see that the call to the async method had ‘await’ before it. This is a C# keyword that tells the method that this async call needs to complete before it can continue.
This is the preferred way of doing this, since the runtime can correctly handle the different threads involved. When this is being executed, the thread currently being used will be made available for other work, and doesn’t block it. Plus, any exceptions that get thrown during the async call get thrown just as you would expect them to.
So, 99% of the time, you just want to await your calls like this:
Why you don’t want to use ‘.Result’
It’s possible to write this async call without using ‘await’, and call ‘.Result’ instead:
Notice that instead of using the ‘await’ keyword, we’re now calling ‘.Result’ directly on the ‘Task’ object returned from the async method.
It compiles, and if you run it, it’ll probably work.
You might think this is a good option, especially since it would appear to work inside non-async methods. But there are a few pitfalls to be aware of, and generally, you will want to avoid using it.
Firstly, calling ‘.Result’ is a blocking call, which means the current thread will stop at this point until the result comes back from the asynchronous call. You don’t want this to happen, because whilst it’s waiting, it’s literally not doing anything. It could get busy working on other requests if it wasn’t blocked, but it’s not. It’s slightly defeating the point of making this an asynchronous call in the first place.
Related to this, using ‘.Result’ within an asynchronous context like this can sometimes result in deadlocks. This is becoming less common with the changes made in later versions of .NET (such as the ‘SynchronizationContext’ being removed from .NET Core), but is still as risk you want to avoid.
The other main issue is around what happens when there’s an exception.
The difference in exceptions for ‘await’ and ‘.Result’
Say you experience a timeout during that HTTP request. When you use ‘await’, you get a ‘TaskCanceledException’, with a pretty decent description:
Exception thrown during a timeout, when the async method is called using ‘await’
Notice the message is absolutely clear on what’s going on:
The request was canceled due to the configured HttpClient.Timeout of 0.001 seconds elapsing.
However, if you use ‘.Result’, the exception is different:
Exception thrown during a timeout, when the async method is called using .Result
Firstly, the type of exception is different. We’ve now got an ‘AggregateException’ instead of ‘TaskCanceledException’. And this exception contains a list of exceptions. In this case, this list contains a single entry, and if you dig into this entry, you find the ‘TaskCanceledException’, but with a generic message:
The inner exception of what was thrown during the .Result call
The message is now:
A task was canceled
A lot less helpful that the other message we had. You might ask what task has been cancelled, or why.
Having exceptions raised as an ‘AggregateException’ makes it a lot harder to write your exception handling logic, since you’ve now got a lot more to check. Plus, the information about why the exception was raised might get lost.
All in all, it’s not great.
Basically, just use ‘await’
There’s no real benefit for using ‘.Result’.
It’s a blocking call, which can have further implications such as deadlocks. And any exceptions raised are a lot more complex to work with, and may miss the extra detail to indicate what the problem is.
Using ‘await’ has neither of these problems, and has been designed specifically for this situation.
So, to call your asynchronous methods properly, please make sure you use ‘await’. It’ll make your async code so much easier to work with!