65.9K
CodeProject is changing. Read more.
Home

Simplifying async calls

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.78/5 (9 votes)

Feb 2, 2014

CPOL
viewsIcon

50844

downloadIcon

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.

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

Where BackupAsync handles the async and await:

  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: 
  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:

  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:

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

Where Backup and UpdateUI is regular methods called asynchronously: 

  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:
  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.