AsyncUtil - C# Helper class to run async methods as sync and vice-versa A useful helper class written in C Sharp to help developers working with async and sync methods in ASP.NET, ASP.NET Core and ASP.NET MVC projects

Classe ASP.NET C# per il controllo e il calcolo formale del Codice Fiscale

The asynchronous programming concept has become a widely used standard in ASP.NET since the .NET Framework 4 thanks to the introduction of the Task class: ASP.NET MVC 4 leverages this approach with the Task<ActionResult> return type, which lets developers write asynchronous action methods. The Tasks object instances are represented by the Task type and related types in the System.Threading.Tasks namespace: working with these kind of objects has been made much easier starting from .NET Framework 4.5 and its await and async keywords, which are arguably less complex from the average developer than previous asynchronous approaches.

To briefly summarize their purpose, we could say that:

  • The await keyword is syntactical shorthand for indicating that a piece of code should asynchronously wait on some other piece of code.
  • The async keyword can be used to mark methods as task-based asynchronous methods and keep the compiler aware of this.

The combination of awaitasync, and the Task object is called the Task-based Asynchronous Pattern (TAP). For more info about such approach, we strongly recommend reading this Microsoft article about async programming in .NET 4

In this post we'll take for granted that the reader knows all the basics of TAP programming in ASP.NET and deal with some specific tips and tricks for working with async methods in C#.

Running sync method as async

Any standard sync method can be run inside a Task by using the following one-liner:

Why should we do that? Well, the answer is simple: the main difference between sync and async methods is that the former ones blocks their execution thread while the latter don't. With this workaround, the "blocking" sync method in a background thread, leaving the foreground one unblocked. This can be very useful in desktop and/or mobile applications, where you would avoid blocking the UI thread while executing resource-intensive and/or time-consuming tasks; it has little use within a web application context, since all threads will spawn from the same thread pool of the request thread and the context will expect them all to complete - or to timeout - before returning the HTTP response.

Run async method as sync

There are a number of ways to run async methods in a synchronous context: let's see them all, from the best one to the worst possible way of do that.

The Good

The best way to run any async method and wait for it to complete is to use the await keyword in the following way:

What await does here is to return the result of the operation immediately and synchronously if the operation has already completed or, if it hasn't, to schedule a continuation to execute the remainder of the async keyword before returning the control to the caller. When the asynchronous operation completes, the scheduled completion will then execute. This is great to avoid deadlocks and can also be used within a try/catch block to get the exception raised by the AsyncMethod itself.

The only downside of using the async keyword is that it requires the containing method to be flagged as async as well. If you are unable to do that, you can only opt for a less secure workaround to achieve the same goal such as those explained below.

The Decent

If you're forced to use a sync containing method, you can use the following helper class:

Then you can use it that way:

This workaround is definitely more complex than the previous one-liner, but it's a decent way to perform an async-within-sync call. As we can see, the helper class basically creates, configure and starts an async task on-the-fly, then unwraps it and synchronously wait for its result: just like the await method above, this approach will prevent deadlocks and could be used within a try/catch block to get the exception raised by the AsyncMethod itself.

UPDATE: if our asynchronous method doesn't need to synchronize back to its context, then we can use an one-liner here as well by making use of the Task.WaitAndUnwrapException method in the following way:

Or the following alternative:

It's worth noting that we do not want to use Task.Wait or Task.Result here, because they both wrap exceptions in AggregateException, which can be very hard to debug and/or test.

IMPORTANT: the above solution is only appropriate if the AsyncMethod does not synchronize back to its context: in other words, every await in the AsyncMethod should end with ConfigureAwait(false). This basically means that it can't update UI elements, access the ASP.NET request context or perform other context-aware activities.

The Bad

Among the various worst ways to run async tasks in a sync way, let's consider the following:

The problem of the above approaches lies in the fact that they all configure a synchronous wait on the execution thread. This basically mean that the main thread cannot be doing any other work while it is synchronously waiting for the task to complete: this is not only unefficient, but it will also pose a serious risk of causing a deadlock the main thread.

To better understand this, consider the following scenario:

  • AsyncMethod() is a method that will only do something whenever its main execution thread is free.
  • SyncMethod() performs an AsyncMethod().Result operation, thus posing itself in a synchronous wait.

That's it: we can clearly see how AsyncMethod() will never be able to return anything, since the main thread is locked by its container SyncMethod() thanks to the synchronous wait configured by Result. In other words, the main thread will be permanently deadlocked by itself.

Related Links

If you want to know more about asynchronous programming in C#, you should definitely take a look at the following must-read posts:

 

About Ryan

IT Project Manager, Web Interface Architect and Lead Developer for many high-traffic web sites & services hosted in Italy and Europe. Since 2010 it's also a lead designer for many App and games for Android, iOS and Windows Phone mobile devices for a number of italian companies. Microsoft MVP for Development Technologies since 2018.

View all posts by Ryan

9 Comments on “AsyncUtil - C# Helper class to run async methods as sync and vice-versa A useful helper class written in C Sharp to help developers working with async and sync methods in ASP.NET, ASP.NET Core and ASP.NET MVC projects

    1. I would definitely try to implement the following CancellationToken approach:

      https://stackoverflow.com/a/16607800/1233379

      It seems the strongest possible way to enforce a timeout behaviour in that async-to-sync scenario, unless the task you’re executing has no built-in timeout features (most of them should have it). The only downside of such approach is that you need to have full control on the task function code, otherwise you’ll have to wrap it on your own function and things will get more complicated… and way less sleek.

  1. I’m getting a warning when trying to use this: “Do not create tasks without passing a TaskScheduler” forf for the .StartNew(task) call.

    1. I think it could be a Code Analyzer error, because the helper class already runs the StartNew(task) command from a TaskFactory which is defined with TaskScheduler.Default to schedule on the thread pool, which is the correct approach to avoid deadlocks.

      If you are bored by that warning you could try to ditch the TaskFactory entirely and just do task.Run(task, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default): it should basically have the same effect, without the warning.

      Let me know if you manage to pull it off.

    1. Task.FromResult() can be useful when you perform an asynchronous operation that needs to returns a Task object, but you already have a synchronous result already computed. For example, I do use Task.FromResult() inside ASP.NET MVC controllers that returns Task but don’t contain any async calls (to avoid the compiler warning message).

      It seems an absolutely an OK approach because the code you need to run is already sync, thus not being a “make async sync while locking the thread” such as .GetAwaiter().GetResult(), .Wait or .Result: however, it’s an entirely different scenario from the article topic.

      Read here for additional info:
      https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-create-pre-computed-tasks?redirectedfrom=MSDN

    1. I would use WaitAndUnwrapException rather than Result, so that the exceptions wouldn’t be wrapped in an AggregateException: other than that your approach is ok, I added it.

Leave a Reply

Your email address will not be published. Required fields are marked *


The reCAPTCHA verification period has expired. Please reload the page.

This site uses Akismet to reduce spam. Learn how your comment data is processed.