Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Simplifying async calls

3.78/5 (9 votes)
2 Feb 2014CPOL 50.8K   277  
How to reduce overhead and complexity of calling async methods.

Introduction

I often find myself revisiting old code to see how a actually implemented the asynchronous calls.
More than once I thought that the async "stuff" could be wrapped so I shouldn't have to remember how to implement it. 

This article is about wrapping the async call into something more easily remembered.  

Typical async use 

This example show how I typically would implement an async call.

C#
public void Backup()
{
  backupInProgress = true;
  Task<String> backup = BackupAsync();
  backup.GetAwaiter().OnCompleted(
    () =>
    {
      BackupStatus = backup.Result;
      backupInProgress = false;
    });
}

Where BackupAsync handles the async and await:

C#
private async Task<String> BackupAsync()
{
  Func<string> a = () =>
    {
      // Do stuff here
    };
  return await Task.Run(a);
}

I normally use the Result from the Function/Task to update logic or UI when the asynchronous method completes.  In the example above a property BackupStatus is set. 

Reducing the code   

The async call can be wrapped into the following method: 
C++
public static void Do(Func<T> func, Action<T> completed)
{
  Task<T> task = AsyncTask(func);
  task.GetAwaiter().OnCompleted(() =>
                                {
                                  if (!task.IsFaulted) // Check if Faulted
                                    completed(task.Result);
                                });
}

Where AsyncTask is defined as below:

C#
private static async Task<T> AsyncTask(Func<T> func)
{
  return await Task.Run(func);
}

Now I can call a Function (func) asynchronously and give the result to an Action (completed) using the following code:

C#
Async<string>.Do(Backup, UpdateUI);

Where Backup and UpdateUI is regular methods called asynchronously: 

C#
private string Backup()
{
  // Do backup
  return "Done"; // return status
}

private void UpdateUI(string status)
{
  BackupStatus = status;
}

Perfect! No more async await, but how do we handle exceptions?
Well we could create an overload that call another method if the Task has IsFaulted set:

public static void Do(Func<T> func, Action<T> completed, Action<Exception> failure)
{
  Task<T> task = AsyncTask(func);
  task.GetAwaiter().OnCompleted(() =>
    {
      if (task.IsFaulted)
        failure(task.Exception);
      else
        completed.Invoke(task.Result);
    });
}
This way we can call the Do method like this:
C#
Async<string>.Do(Backup, UpdateUI, HandleException);  

Where HandleException: 

private void HandleException(Exception parameter)
{
   // Handle exception
}  


Please look at the provided sample for additional information. 

History 

My initial thoughts.

License

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