Runar Ovesen Hjerpbakk

Software Philosopher

Async Method Caller - Easy async Without await

tl;dr: AsyncMethodCaller is used to call methods asynchronously. Execution will continue with other methods after the asynchronous call completes. Use this if you cannot use async and await to easily make testable asynchronous calls. Very useful in ViewModels.

AsyncMethodCaller conceptual diagram

The Problem

C# has over its lifetime accumulated many asynchronous programming models:

Before async and await, background workers have long been a preferred method for making asynchronous calls and creating non-blocking UIs in MVVM ViewModels. This is a simple example:

 public class ViewModelWithBackgroundWorker { private
readonly BackgroundWorker worker; public ViewModelWithBackgroundWorker() {
worker = new BackgroundWorker(); worker.DoWork += DoSomething;
worker.RunWorkerCompleted += WorkCompleted; } public string Message { get; set;
} public string Result { get; set; } public void ExecuteAsync() { Message =
"Loading..."; worker.RunWorkerAsync(); } private void DoSomething(object sender,
DoWorkEventArgs e) { e.Result = "Result"; } private void WorkCompleted(object
sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) {
HandleError(e.Error); } else { Message = "Completed"; Result = (string)e.Result;
} } private void HandleError(Exception exception) { Message = exception.Message;
} } 

Unfortunately, this practice has a couple of obvious deficiencies:

  • Testing the correctness of the asynchronous execution is not straight forward and often involve inheriting from the View Model
  • The code is verbose and the program flow can be hard to follow
  • Multiple BackgroundWorkers might be needed if different asynchronous operations are to be supported

The Solution

The obvious solution is using async and await from C# 5. C# 5 does not support Windows XP however, making this solution unattainable for many organizations.

Therefore I created AsyncMethodCaller. AsyncMethodCaller is used to call methods asynchronously and continue with other methods after execution completes. If you cannot use async and await, it makes asynchronous calls easy to understand and test.

AsyncMethodCaller sequence diagram

The example from before can now be rewritten, with unit tests!

 public class ViewModelWithAsyncMethodCaller { private
readonly AsyncMethodCaller asyncMethodCaller; public
ViewModelWithAsyncMethodCaller(AsyncMethodCaller asyncMethodCaller) {
this.asyncMethodCaller = asyncMethodCaller ?? new AsyncMethodCaller(); } public
string Message { get; set; } public string Result { get; set; } public void
ExecuteAsync() { Message = "Loading...";
asyncMethodCaller.CallMethodAndContinue(DoSomething, WorkCompleted,
HandleError); } private string DoSomething() { return "Result"; } private void
WorkCompleted(string result) { Message = "Completed"; Result = result; } private
void HandleError(Exception exception) { Message = exception.Message; } }
[TestFixture] public class ViewModelTests { [Test] public void DoSomething() {
var asyncMethodCaller = new TestAsyncMethodCaller(); var viewModel = new
ViewModelWithAsyncMethodCaller(asyncMethodCaller); viewModel.ExecuteAsync();
Assert.AreEqual("Loading...", viewModel.Message);
asyncMethodCaller.StartServiceAndWait(); Assert.AreEqual("Result",
viewModel.Result); Assert.AreEqual("Completed", viewModel.Message); } } 

AsyncMethodCaller thus gives you the following advantages:

  • The asynchronous code is isolated from the ViewModel-logic
  • The code can be tested without inheritance, using tests before, under and after the asynchronous call
  • Program flow is easy to follow
  • Only one AsyncMethodCaller is needed

The source code is available on GitHub or as a nuget-package.