Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Asynchronous Programming in .NET – Motivation and Unit Testing

3.50/5 (5 votes)
21 May 2018CPOL8 min read 22.4K  
Asynchronous Programming in .NET – Motivation and Unit Testing

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.

Image 1

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

Image 2

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

Image 3

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:

C#
public class WebAccess
{
    public async Task<int> AccessRubiksCodeAsync()
    {
        HttpClient client = new HttpClient();

        var getContent = client.GetStringAsync("http://rubikscode.net");

        LogToConsole("Yay!");

        string content = await getContent;

        return content.Length;
    }

    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.");
        Console.WriteLine("message");
    }
}
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 method is used. We’ve put Async suffix at the end of the name of the function, which is the standard naming convention for asynchronous methods. AccessRubiksCodeAsync method is calling some operations that are synchronous, as well, like the function LogToConsole. It is important to realize that GetStringAsync method is asynchronous too and it returns Task. This Tas<wbr />k is later run by the await operator.

Image 4

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:

Image 5

In the first step (marked with 1), AccessRubiksCodeAsync method creates an instance of the HttpClient and calls GetStringAsync method of this class. The goal is to download the content of the website in a form of a string. If something unexpected happens that blocks GetStringAsync method, e.g., the website is taking too long to download, this method yields control to its caller. That is how it avoids blocking resources. Apart from that, this method returns Task, which AccessRubiksCodeAsync assigns to the variable getContent. Later in the code, this variable is used in combination with await operator.

Now, since we haven’t used await operator on getContent yet, AccessRubik<wbr />sCodeAsync can continue with other operations that are not depending on the result of getContent task. So, the LogToConsole method can be run in a synchronous manner (step 2). This means that this method will take control, do its job and only then give control back to AccessRubiksCodeAsync method.

After that, this method is calling getContent with await operator (step 3). This means that at this moment, this method requires the result from GetStringAsync method. If this GetStringAsync is still not ready, AccessRubiksCodeAsync is suspending its progress and returns control to its caller. Of course, bit benefit of having this kind flow is that we “gave some time” to GetStringAsync method, and meanwhile, we have run synchronous parts of the code. When content is downloaded, its length is returned as a result (step 4).

Unit Testing Asynchronous Methods

Image 6

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:

C#
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 classWebAcces<wbr />sTests.

C#
public class WebAccessTests
{
    [Fact]
    public async Task AccessRubiksCode_NoCondition_ExpectedResult()
    {
        var webAccess = new WebAccess();

        var result = await webAccess.AccessRubiksCodeAsync();

        Assert.NotEqual(0, result);
    }
}
Now, let’s analyze the 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 method of WebAccess class with await operator. We could skip this and call this method without await operator, and keep the public void notion, but this will not end up in the behavior we expected.

What will happen if we do this – call the async method without await operator? Well, in that case, this async method will be fired separately, and in the meantime, the calling method will continue executing. Since we didn’t await it, you’ll never know whether and when it has completed. 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 method and retrieve the result. Finally, in “assert” phase, we are checking the validity of the result.

Conclusion

Asynchronous programming is a somewhat standard functionality of .NET for a 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!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)