As of C# 5.0 which comes with .NET 4.5 and with Visual Studio 2012, we can use the new asynchronous pattern involving use of the async and await keywords. There are many different points of views regarding if this is a better approach than what we have seen before with regards to readability and usability. We will walk through an example and see how it is ‘different’ from the current practices.
Linear versus non-linear code
Most software engineers are used to programming in a linear manner, at least that is how they are taught when they begin their careers. When a program is written in a linear manner that means the source code will be read somewhat like what the diagram in Figure 1 visualizes. This assumes that we have an order system in place that will help us to fetch a collection of orders from somewhere.
Humans are used to reading from top to bottom, even if it starts from left or right. If we have something that disturbs this flow of content, we are going to be confused and spend more efforts than what is really necessary. Event based applications often have these non-linear constructs.
This article is published from the DNC Magazine for .NET Developers and Architects. Subscribe to this magazine for FREE and download all previous and current editions
The flow of an event-based system is such that it fires off a call somewhere and expects the result to be delivered through a raised event, can be visualized like the diagram in Figure 2 shows. At a first glance the two sequences might not seem very different but if we assume that GetAllOrders returns void it would not be very straight forward how we retrieve the list of orders.
Without looking at the actual code, we can identify that the linear approach is much more pleasant to handle and it is less error prone. Errors in this case might not be actual runtime errors or compilation errors, but errors in usage; since the lack of lucidity.
There is one big advantage with the event based approach; it will let us conform to an event-based asynchronous pattern.
When you look at a method, you want to understand everything about the methods purpose. This means that if you have a method that is called ReloadOrdersAndRefreshUI you want to understand where the orders are loaded from, how it’s added onto the UI and what happens when the method ends. That can be hard to achieve with an event-based approach.
Another benefit from this is that we can write asynchronous code in GetAllOrders as long as when we raise the LoadOrdersCompleted event, we are back on the calling thread.
Introducing a new pattern
Let us assume that we are working on our system that uses the OrderHandler mentioned before and the actual implementation will use a linear approach. To simulate a small portion of a real order system, the OrderHandler and Order will look like the following:
class Order
{
public string OrderNumber { get; set; }
public decimal OrderTotal { get; set; }
public string Reference { get; set; }
}
class OrderHandler
{
private readonly IEnumerable _orders;
public OrderHandler()
{
_orders = new[]
{
new Order {OrderNumber = "F1", OrderTotal = 100, Reference = "Filip"},
new Order {OrderNumber = "F1", OrderTotal = 100, Reference = "Filip"}
};
}
public IEnumerable GetAllOrders()
{
return _orders;
}
}
Since we don’t use a real data source in this example, we need to make it a little bit more interesting. As this is about asynchronous programming, we want to have something to ask for in an asynchronous manner. In order to simulate this, we can simply add:
System.Threading.ManualResetEvent(false).WaitOne(2000) in GetAllOrders:
public IEnumerable GetAllOrders()
{
System.Threading.ManualResetEvent(false).WaitOne(2000);
return _orders;
}
The reason that we aren’t using Thread.Sleep here is because this is going to be inside a Windows 8 Store Application. The goal here is that we are going to have a button that we can press in our Windows 8 Store Application which loads our orders into a list. Then we can compare the user experience and the code prior to the asynchronous code being added.
If you’ve created a new blank Windows 8 Store Application project, you can add the following XAML to your MainPage.xaml:
Before we can actually run the application we need to add some things to the code file as well. There needs to be an event handler for the click event and we also want to set a default value on the information text block:
public MainPage()
{
this.InitializeComponent();
Information.Text = "No orders have been loaded yet.";
}
private void LoadOrders_Click(object sender, RoutedEventArgs e)
{
OrderLoadingProgress.Visibility = Visibility.Visible;
var orderHandler = new OrderHandler();
var orders = orderHandler.GetAllOrders();
OrderLoadingProgress.Visibility = Visibility.Collapsed;
}
This will give us a nice looking application that looks like this when we run it in the built in simulator of Visual Studio 2012
To see the application bar at the bottom, simply enable the basic touch mode by pressing this image in the right hand menu then swipe from the bottom up.
Now when you press the Load orders button, you will notice that you will not see any loading indicator and that the button is left in its pressed state for 2 seconds. This is because we are locking up the application.
Previously we could have solved this by wrapping the code in a BackgroundWorker. That when finished would have raised an event in which we had to invoke a delegate in order for us to change the UI. This is a non-linear approach which tends to mess up the readability of the code. In an older application that is not WinRT, using a BackgroundWorker would have looked something like this:
public sealed partial class MainPage : Page
{
private BackgroundWorker _worker = new BackgroundWorker();
public MainPage()
{
InitializeComponent();
_worker.RunWorkerCompleted += WorkerRunWorkerCompleted;
_worker.DoWork += WorkerDoWork;
}
void WorkerDoWork(object sender, DoWorkEventArgs e)
{
var orderHandler = new OrderHandler();
var orders = orderHandler.GetAllOrders();
}
private void LoadOrders_Click(object sender, RoutedEventArgs e)
{
OrderLoadingProgress.Visibility = Visibility.Visible;
_worker.RunWorkerAsync();
}
void WorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Dispatcher.BeginInvoke(new Action(() =>
{
// Update the UI
OrderLoadingProgress.Visibility = Visibility.Collapsed;
}));
}
}
The BackgroundWorker is what is known as event-based asynchronicity, the pattern is called event-based asynchronous pattern (EAP). This tend to make the code messier than it could be and since it is also written in a non-linear manner, our brains will have a harder time getting a complete overview of it as fast as it could.
In WinRT however, there is no BackgroundWorker so we have to adapt to the new linear approach, which is only a good thing!
Our solution to this is to adapt to the new pattern introduced in .NET 4.5, async & await. When we use async & await it is mandatory that we are using it together with the task parallel library (TPL). The principle is that whenever a method needs to run asynchronously, we mark it as such. This means that the method will have something that we are waiting for to get back to, a continuation. The marking for where the continuation block will be, is made by defining an ‘awaitable’ section, hence we ask to await the task to finish.
Based on the original code, without the BackgroundWorker we can just make some small changes to the click handler in order for it to be used in an asynchronous manner. First we need to mark the method as async, this is as easy as just adding the keyword to the method signature:
private async void LoadOrders_Click(object sender, RoutedEventArgs e)
Be very careful when using async and void together, the only reason that marking a method with async when the return type is void, is because of event handlers. Never mark a method as async when the return type is void if it is not an event handler! Async & await are always used together, if a method is marked as async and does not have something awaitable in it; it will simply run synchronously.
So the next thing that we want to do is actually having something that we can await, in our case this is the call to GetAllOrders. As this is what this is what takes up the most of the time, we want this to run in a separate task. We can simply wrap the method call in a task that expects to return an IEnumerable like this:
Task
The above is what we want to await, let’s take a look at what we had from the start and how it compares to what we have now:
// Before
var orders = orderHandler.GetAllOrders();
// After
var orders = await Task
When we add await in front of a task, the type that the variable orders will be is what the task is expected to return; which in this case is IEnumerable>. This means that all we had to do in order to make this method asynchronous was to mark it as such and just wrap the long running method call in a task.
What happens internally is that we will get a state machine that keeps track of when the task is finished. Everything below of the awaitable block will be put into a continuation block. If you are familiar with TPL and the continuation on a task, this is similar to that except that we are back on the calling thread when we reach the continuation! This is an important distinction, because that means that we can have our method look like this, without any dispatcher invocations:
private async void LoadOrders_Click(object sender, RoutedEventArgs e)
{
OrderLoadingProgress.Visibility = Visibility.Visible;
var orderHandler = new OrderHandler();
var orderTask = Task
var orders = await orderTask;
Orders.Items.Clear();
foreach (var order in orders)
Orders.Items.Add(order);
OrderLoadingProgress.Visibility = Visibility.Collapsed;
}
As you can see, we can simply change things on the UI after the awaitable block without using the dispatcher as we previously would have when using EAP or TPL. We can now run this application and
load the orders without the UI locking up and then having a nice list of order numbers presented to us.
We can thus see that using this new approach will give us more readable and linear code; this is what we are most use to seeing. Of course, there are always ways to write less readable code even with the best of patterns. Async & Await sure helps along the way to create more readable and maintainable code.
Conclusion
Async & Await makes it very easy to create readable and maintainable asynchronous solutions. Prior to the release of this, we had to fall back on event-based methods which tended to introduce confusion. As we are in an era where almost any computer has at least two cores, even the mobile phones, we will be seeing a lot more parallel and asynchronous code. As this is getting much easier with async & await it no longer has to be an issue in the development phase to introduce it. We can avoid cross-thread problems that often arise when using tasks or event-based asynchronicity due to not using the dispatchers or invocation capabilities. With this new pattern we can step away from that way of thinking and focus on creating responsive and maintainable solutions.
Of course this is not the answer to everything, we still have problems that can arise and complex scenarios where this approach also can cause confusion. But as with anything use it where it is appropriate and where it benefits the application life-cycle.
The entire source code of this article can be downloaded at http://bit.ly/dncmag-asaw (Github)
This article was written by Filip Ekberg for the Free DNC .NET Magazine. Filip is a Software Engineer with a big heart for programming in C#. Most recently Filip is the author of the book C# Smorgasbord, that covers a vast variety of different technologies, patterns & practices. You can Follow Filip on twitter @fekberg and read his articles on fekberg.com
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Filip is a Microsoft Visual C# MVP, Book author, Pluralsight author and Senior Consultant at Readify. He is the author of the book C# Smorgasbord, which covers a vast variety of different technologies, patterns and practices. Follow Filip on twitter @fekberg and read his articles on
fekberg.com