It has been a long time since .NET version 4.5 was released. To refresh our memory, that happened on August 15th, 2012. Yes, six years ago. Feel old yet? Well, it was not my intention to bum you out but to remind you about some of the highlights of .NET release. One of the main features that this version brought was asynchronous programming using async/await methods. Basically, the guys from Microsoft made the compiler do work that developers used to do by keeping the logical structure that resembles synchronous code.
You see, back then Windows Phone was still a thing, and making applications for these platforms had certain limitations. The main one was that Windows Phone, unlike desktop applications, introduced hard limit in which no method could block for more than 50ms. This, in turn, meant that there was no more blocking of the UI for the developers, which led to the necessity for some sort of asynchronicity in the code. .NET 4.5 represents the response to this necessity.
So, why am I writing about something that happened more than half a decade ago? Well, I noticed that even though this is an old topic, there are still a lot of engineers that struggle with the concept. To quote Mike James from iProgrammer:
Often the programmer is fully aware that what they are doing is object oriented but only vaguely aware that they are writing asynchronous code.
That is why I will try to sum up the most important parts of this style of programming in a few blogs posts. Also, we will try to identify situations in which we should use this programming style, as well as the situations when we should avoid it. So, let’s dive right into it!
Motivation and Use Cases
Essentially, this style of programming is applicable to anywhere you need the ability to do something while waiting for something else to be complete. Years of usage of this tool have actually given us the ability to realize where we should use it. It is great for user experience, and in general for event-based systems, e.g. CPU-based parallelism or working with files.
Any activity that is potentially blocking, such as access to the web, is a good candidate for this approach. If any of these blocking activities end up in a synchronous process, the entire application is blocked. On the other hand, if this activity is a part of an asynchronous process, the application can continue working with other tasks until the activity is done.
Of course, you don’t need to abuse this ability. For example, we shouldn’t asynchronously update records that are dependent. It is generally a bad idea and our data will get out of sync very quickly. Apart from that, this concept is sometimes overused. For example, if we are working on some simple actions and operations we should consider more orthodox approaches. Using asynchronous concepts in these cases may, in fact, cause more overhead than benefits.
Async/Await and Return Types
The asynchronous mechanism is implemented in .NET by using async/await keywords in our code. We use the async operator to mark our methods as asynchronous. Only methods with this operator methods can use await operator in them. Await operator, on the other hand, is telling to the compiler that async method in which it has been used can’t continue past that point until the awaited asynchronous task is complete. Basically, it suspends the execution of the method until awaited task is done. Methods that are marked with async operator also can be called with await operator from the other methods.
Another important thing to mention is that async methods must return Task class or Task class. This is because in this method await operator is applied to the Task that is returned from another async method. To sum it up, the asynchronous mechanism is in .NET implemented like this:
- We use the async operator to mark the methods that we want to be asynchronous. These methods must return Task class or Task class.
- When we are calling methods that are marked with the async operator, we use await operator. This operator will run the task that asynchronous method returned.
How does that look into the code? Take a look at this example WebAccess.cs class:
|public class WebAccess|
|public async Task<int> AccessRubiksCodeAsync()|
|HttpClient client = new HttpClient();|
|var getContent = client.GetStringAsync("http://rubikscode.net");|
|string content = await getContent;|
|private void LogToConsole(string message)|
|Console.WriteLine("At the moment I am actually listening to the new NIN song…");|
|Console.WriteLine("It is pretty cool…like something of David Bowie's – Blackstar.");|
The goal of this class is to access this website in a non-blocking manner and to get the length of the response body, for which AccessRubiksCodeAsync me
Notice how we attained the structure of the synchronous code, which is awesome. Even though we are calling await operator and essentially running asynchronous task our code looks pretty neat and simple. This is one of the reasons why async/await mechanism gained a lot of popularity.
So, what happens if GetStringAsync method takes too long to answer? Here is how the workflow goes:
In the first step (marked with 1) AccessRubiksCodeAsync
Now, since we haven’t used await operator on getContent yet, AccessRubik
After that, this method is calling getContent with await
Unit Testing Asynchronous Methods
Unit testing is actually one great example of how async methods are initiated. In this example, I’ve used xUnit, but async/await mechanism is supported in other unit testing frameworks like NUnit and MSTests. If you want to install xUnit to your project enter these commands in Package Manager Console:
Install-Package xunit Install-Package xunit.runner.console Install-Package xunit.runner.visualstudio Update-Package
Ok, this should get you up to speed with xUnit. Now let’s take a look at our test class for WebAccess class – WebAcces
|public class WebAccessTests|
|public async Task AccessRubiksCode_NoCondition_ExpectedResult()|
|var webAccess = new WebAccess();|
|var result = await webAccess.AccessRubiksCodeAsync();|
Now, let’s analyze important parts of this test. Firstly, notice how our test method is marked with public async Task, unlike the standard public void. This is done like this because in our test method we are actually calling AccessRubiksCodeAsync
What will happen if we do this – call the async method without await operator? Well, in that case, this async method will be executed as a synchronous method, meaning it will block the thread. Again, this is bad for UI and web operations and scaling becomes impossible. This can be used as an advantage in certain situations of course, but it is important to know how this mechanism is working.
Apart from that, there are no crucial changes into test structure. We are first creating an instance of WebAccess class in “arrange” phase. In “act” phase we are using await operator to initiate AccessRubiksCodeAsync
Asynchronous programming is a somewhat standard functionality of .NET for the number of years. Still, sometimes I get the notion that less experienced programmers don’t quite get the point of it. Especially the ones that don’t have experience with some other technologies where this mechanism is directly used in the technology itself, like Node.js. Or they are familiar with it and try to use it in every situation.
In this article, I tried to explain how asynchronous programming is done in the .NET world from the high-level. In next few articles, we will go deeper into the subject and cover some other aspects of this style, as well.
Thank you for reading!
Read more posts from the author at Rubik’s Code.