Async Programming

Patterns for Asynchronous MVVM Applications: Services

Stephen Cleary

This is the third article in a series on combining async and await with the established Model-View-ViewModel (MVVM) pattern. In the first article, I developed a method for data binding to an asynchronous operation. In the second, I considered a few possible implementations of an asynchronous ICommand. Now, I’ll turn to the service layer and address asynchronous services.

I’m not going to deal with a UI at all. In fact, the patterns in this article aren’t specific to MVVM; they pertain equally well to any type of application. The asynchronous data binding and command patterns explored in my earlier articles are quite new; the asynchronous service patterns in this article are more established. Still, even established patterns are just patterns.

Asynchronous Interfaces

“Program to an interface, not an implementation.” As this quote from “Design Patterns: Elements of Reusable Object-Oriented Software” (Addison-Wesley, 1994, p. 18) suggests, interfaces are a critical component of proper object-oriented design. They allow your code to use an abstraction rather than a concrete type, and they give your code a “junction point” you can splice into for unit testing. But is it possible to create an interface with asynchronous methods?

The answer is yes. The following code defines an interface with an asynchronous method:

public interface IMyService
{
  Task<int> DownloadAndCountBytesAsync(string url);
}

The service implementation is straightforward:

public sealed class MyService : IMyService
{
  public async Task<int> DownloadAndCountBytesAsync(string url)
  {
    await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
    using (var client = new HttpClient())
    {
      var data = await 
        client.GetByteArrayAsync(url).ConfigureAwait(false);
      return data.Length;
    }
  }
}

Figure 1 shows how the code that consumes the service calls the asynchronous method defined on the interface.

Figure 1 UseMyService.cs: Calling the Async Method Defined on the Interface

public sealed class UseMyService
{
  private readonly IMyService _service;
  public UseMyService(IMyService service)
  {
    _service = service;
  }
  public async Task<bool> IsLargePageAsync(string url)
  {
    var byteCount = 
      await _service.DownloadAndCountBytesAsync(url);
    return byteCount > 1024;
  }
}

This may seem like an overly simplistic example, but it illustrates some important lessons about asynchronous methods.

The first lesson is: Methods are not awaitable, types are. It is the type of an expression that determines whether that expression is awaitable. In particular, UseMyService.IsLargePageAsync awaits the result of IMyService.DownloadAndCountBytesAsync. The interface method is not (and cannot be) marked async. IsLargePageAsync can use await because the interface method returns a Task, and tasks are awaitable.

The second lesson is: Async is an implementation detail. UseMyService neither knows nor cares whether the interface methods are implemented using async or not. The consuming code cares only that the method returns a task. Using async and await is a common way to implement a task-returning method, but it’s not the only way. For example, the code in Figure 2 uses a common pattern for overloading asynchronous methods.

Figure 2 AsyncOverloadExample.cs: Using a Common Pattern for Overloading Async Methods

class AsyncOverloadExample
{
  public async Task<int> 
    RetrieveAnswerAsync(CancellationToken cancellationToken)
  {
    await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
    return 42;
  }
  public Task<int> RetrieveAnswerAsync()
  {
    return RetrieveAnswerAsync(CancellationToken.None);
  }
}

Note that one overload merely calls the other and returns its task directly. It’s possible to write that overload using async and await, but that would only add overhead and provide no benefit.

Asynchronous Unit Testing

There are other options for implementing task-returning methods. Task.FromResult is a common choice for unit test stubs, because it’s the easiest way to create a completed task. The following code defines a stub implementation of the service:

class MyServiceStub : IMyService
{
  public int DownloadAndCountBytesAsyncResult { get; set; }
  public Task<int> DownloadAndCountBytesAsync(string url)
  {
    return Task.FromResult(DownloadAndCountBytesAsyncResult);
  }
}

You can use this stub implementation to test UseMyService, as shown in Figure 3.

Figure 3 UseMyServiceUnitTests.cs: Stub Implementation to Test UseMyService

[TestClass]
public class UseMyServiceUnitTests
{
  [TestMethod]
  public async Task UrlCount1024_IsSmall()
  {
    IMyService service = new MyServiceStub { 
      DownloadAndCountBytesAsyncResult = 1024 
	};
    var logic = new UseMyService(service);
    var result = await 
      logic.IsLargePageAsync("http://www.example.com/");
    Assert.IsFalse(result);
  }
  [TestMethod]
  public async Task UrlCount1025_IsLarge()
  {
    IMyService service = new MyServiceStub { 
      DownloadAndCountBytesAsyncResult = 1025 
	};
    var logic = new UseMyService(service);
    var result = await 
      logic.IsLargePageAsync("http://www.example.com/");
    Assert.IsTrue(result);
  }
}

This example code uses MSTest, but most other modern unit test frameworks also support asynchronous unit tests. Just make sure your unit tests return task; avoid async void unit test methods. Most unit test frameworks do not support async void unit test methods.

When unit testing synchronous methods, it’s important to test how the code behaves both in success and failure conditions. Asynchronous methods add a wrinkle: It’s possible for an asynchronous service to succeed or throw an exception, synchronously or asynchronously. You can test all four of these combinations if you want, but I find it’s usually sufficient to test at least asynchronous success and asynchronous failure, plus synchronous success if necessary. The synchronous success test is useful because the await operator will act differently if its operation has already completed. However, I don’t find the synchronous failure test as useful, because failure isn’t immediate with most asynchronous operations.

As of this writing, some popular mocking and stubbing frameworks will return default(T) unless you modify that behavior. The default mocking behavior doesn’t work well with asynchronous methods because asynchronous methods should never return a null task (according to the Task-based Asynchronous Pattern, which you’ll find at bit.ly/1ifhkK2). The proper default behavior would be to return Task.FromResult(default(T)). This is a common problem when unit testing asynchronous code; if you’re seeing unexpected NullReferenceExceptions in your tests, ensure the mock types are implementing all the task-returning methods. I hope that mocking and stubbing frameworks will become more async-aware in the future, and implement better default behavior for asynchronous methods.

Asynchronous Factories

The patterns so far have demonstrated how to define an interface with an asynchronous method; how to implement it in a service; and how to define a stub for testing purposes. These are sufficient for most asynchronous services, but there’s a whole other level of complexity that applies when a service implementation must do some asynchronous work before it’s ready to be used. Let me describe how to handle the situation where you need an asynchronous constructor.

Constructors can’t be async, but static methods can. One way of faking an asynchronous constructor is to implement an asynchronous factory method, as shown in Figure 4.

Figure 4 Service with an Asynchronous Factory Method

interface IUniversalAnswerService
{
  int Answer { get; }
}
class UniversalAnswerService : IUniversalAnswerService
{
  private UniversalAnswerService()
  {
  }
  private async Task InitializeAsync()
  {
    await Task.Delay(TimeSpan.FromSeconds(2));
    Answer = 42;
  }
  public static async Task<UniversalAnswerService> CreateAsync()
  {
    var ret = new UniversalAnswerService();
    await ret.InitializeAsync();
    return ret;
  }
  public int Answer { get; private set; }
}

I really like the asynchronous factory approach because it can’t be misused. Calling code can’t invoke the constructor directly; it must use the factory method to get an instance, and the instance is fully initialized before it’s returned. However, this can’t be used in some scenarios. As of this writing, inversion of control (IoC) and dependency injection (DI) frameworks don’t understand any conventions for asynchronous factory methods. If you’re injecting your services using an IoC/DI container, you’ll need an alternative approach.

Asynchronous Resources

In some cases, asynchronous initialization is needed only once, to initialize shared resources. Stephen Toub developed an Async­Lazy<T> type ( bit.ly/1cVC3nb), which is also available as a part of my AsyncEx library ( bit.ly/1iZBHOW). AsyncLazy<T> combines Lazy<T> with Task<T>. Specifically, it’s a Lazy<Task<T>>, a lazy type that supports asynchronous factory methods. The Lazy<T> layer provides thread-safe lazy initialization, ensuring the factory method is only executed once; the Task<T> layer provides asynchronous support, permitting callers to asynchronously wait for the factory method to complete.

Figure 5 presents a slightly simplified definition of AsyncLazy<T>. Figure 6 shows how AsyncLazy<T> can be used within a type.

Figure 5 Definition of AsyncLazy<T>

// Provides support for asynchronous lazy initialization.
// This type is fully thread-safe.
public sealed class AsyncLazy<T>
{
  private readonly Lazy<Task<T>> instance;
  public AsyncLazy(Func<Task<T>> factory)
  {
    instance = new Lazy<Task<T>>(() => Task.Run(factory));
  }
  // Asynchronous infrastructure support.
  // Permits instances of this type to be awaited directly.
  public TaskAwaiter<T> GetAwaiter()
  {
    return instance.Value.GetAwaiter();
  }
}

Figure 6 AsyncLazy<T> Used in a Type

class MyServiceSharingAsyncResource
{
  private static readonly AsyncLazy<int> _resource =
    new AsyncLazy<int>(async () =>
    {
       await Task.Delay(TimeSpan.FromSeconds(2));
       return 42;
    });
  public async Task<int> GetAnswerTimes2Async()
  {
    int answer = await _resource;
    return answer * 2;
  }
}

This service defines a single shared “resource” that must be constructed asynchronously. Any methods of any instances of this service can depend on that resource and await it directly. The first time the AsyncLazy<T> instance is awaited, it will start the asynchronous factory method once on a thread pool thread. Any other simultaneous access to that same instance from another thread will wait until the asynchronous factory method has been queued to the thread pool.

The synchronous, thread-safe part of the AsyncLazy<T> behav­ior is handled by the Lazy<T> layer. The time spent blocking is very short: each thread waits only for the factory method to be queued to the thread pool; they don’t wait for it to execute. Once the Task<T> is returned from the factory method, then the Lazy<T> layer’s job is over. The same Task<T> instance is shared with every await. Neither asynchronous factory methods nor asynchronous lazy initialization will ever expose an instance of T until its asynchronous initialization has completed. This protects against accidental misuse of the type.

AsyncLazy<T> is great for one particular kind of problem: asynchronous initialization of a shared resource. However, it can be awkward to use in other scenarios. In particular, if a service instance needs an asynchronous constructor, you can define an “inner” service type that does the asynchronous initialization and use AsyncLazy<T> to wrap the inner instance within the “outer” service type. But that leads to cumbersome and tedious code, with all methods depending on the same inner instance. In such scenarios, a true “asynchronous constructor” would be more elegant.

A Misstep

Before I go into my preferred solution, I want to point out a somewhat common misstep. When developers are confronted with asynchronous work to do in a constructor (which can’t be async), the workaround can be something like the code in Figure 7.

Figure 7 Workaround When Confronted with Async Work To Do in a Constructor

class BadService
{
  public BadService()
  {
    InitializeAsync();
  }
  // BAD CODE!!
  private async void InitializeAsync()
  {
    await Task.Delay(TimeSpan.FromSeconds(2));
    Answer = 42;
  }
  public int Answer { get; private set; }
}

But there are some serious problems with this approach. First, there’s no way to tell when the initialization has completed; second, any exceptions from the initialization will be handled in the usual async void manner, commonly crashing the application. If InitializeAsync was async task instead of async void, the situation would barely be improved: There would still be no way to tell when the initialization completed, and any exceptions would be silently ignored. There’s a better way!

The Asynchronous Initialization Pattern

Most reflection-based creation code (IoC/DI frameworks, Activator.CreateInstance and so forth) assumes your type has a constructor, and constructors can’t be asynchronous. If you’re in this situation, you’re forced to return an instance that hasn’t been (asynchronously) initialized. The purpose of the asynchronous initialization pattern is to provide a standard way of handling this situation, to mitigate the problem of uninitialized instances.

First, I define a “marker” interface. If a type needs asynchronous initialization, it implements this interface:

/// <summary>
/// Marks a type as requiring asynchronous initialization and
/// provides the result of that initialization.
/// </summary>
public interface IAsyncInitialization
{
  /// <summary>
  /// The result of the asynchronous initialization of this instance.
  /// </summary>
  Task Initialization { get; }
}

At first glance, a property of type Task feels odd. I believe it’s appropriate, though, because the asynchronous operation (initializing the instance) is an instance-level operation. So the Initialization property pertains to the instance as a whole.

When I implement this interface, I prefer to do so with an actual async method, which I name InitializeAsync by convention, as Figure 8 shows:

Figure 8 Service Implementing the InitializeAsync Method

class UniversalAnswerService : 
  IUniversalAnswerService, IAsyncInitialization
{
  public UniversalAnswerService()
  {
    Initialization = InitializeAsync();
  }
  public Task Initialization { get; private set; }
  private async Task InitializeAsync()
  {
    await Task.Delay(TimeSpan.FromSeconds(2));
    Answer = 42;
  }
  public int Answer { get; private set; }
}

The constructor is quite simple; it starts the asynchronous initialization (by calling InitializeAsync) and then sets the Initialization property. That Initialization property provides the results of the InitializeAsync method: when InitializeAsync completes, the Initialization task completes, and if there are any errors, they will be surfaced through the Initialization task.

When the constructor completes, the initialization might not yet be complete, so the consuming code has to be careful. The code using the service has the responsibility to ensure the initialization is complete before calling any other methods. The following code creates and initializes a service instance:

async Task<int> AnswerTimes2Async()
{
  var service = new UniversalAnswerService();
  // Danger! The service is uninitialized here; "Answer" is 0!
  await service.Initialization;
  // OK, the service is initialized and Answer is 42.
  return service.Answer * 2;
}

In a more realistic IoC/DI scenario, the consuming code only gets an instance implementing IUniversalAnswerService, and has to test whether it implements IAsyncInitialization. This is a useful technique; it allows the asynchronous initialization to be an implementation detail of the type. For example, stub types will probably not use asynchronous initialization (unless you’re actually testing that the consuming code will wait for the service to be initialized). The following code is a more realistic use of my answer service:

async Task<int> 
  AnswerTimes2Async(IUniversalAnswerService service)
{
  var asyncService = service as IAsyncInitialization;
  if (asyncService != null)
    await asyncService.Initialization;
  return service.Answer * 2;
}

Before continuing with the asynchronous initialization pattern, I should point out an important alternative. It’s possible to expose the service members as asynchronous methods that internally await the initialization of their own objects. Figure 9 shows what this kind of object would look like.

Figure 9 Service That Awaits Its Own Initialization

class UniversalAnswerService
{
  private int _answer;
  public UniversalAnswerService()
  {
    Initialization = InitializeAsync();
  }
  public Task Initialization { get; private set; }
  private async Task InitializeAsync()
  {
    await Task.Delay(TimeSpan.FromSeconds(2));
    _answer = 42;
  }
  public Task<int> GetAnswerAsync()
  {
    await Initialization;
    return _answer;
  }
}

I like this approach because it isn’t possible to misuse an object that hasn’t yet been initialized. However, it limits the API of the service, because any member that depends on initialization must be exposed as an asynchronous method. In the preceding example, the Answer property was replaced with a GetAnswerAsync method.

Composing the Asynchronous Initialization Pattern

Let’s say I’m defining a service that depends on several other services. When I introduce the asynchronous initialization pattern for my services, any of those services might require asynchronous initialization. The code for checking whether those services implement IAsyncInitialization can get somewhat tedious, but I can easily define a helper type:

public static class AsyncInitialization
{
  public static Task 
    EnsureInitializedAsync(IEnumerable<object> instances)
  {
    return Task.WhenAll(
      instances.OfType<IAsyncInitialization>()
        .Select(x => x.Initialization));
  }
  public static Task EnsureInitializedAsync(params object[] instances)
  {
    return EnsureInitializedAsync(instances.AsEnumerable());
  }
}

The helper methods take any number of instances of any type, filter out any that don’t implement IAsyncInitialization, and then asynchronously wait for all the Initialization tasks to complete.

With these helper methods in place, creating a compound service is straightforward. The service in Figure 10 takes two instances of the answer service as dependencies, and averages their results.

Figure 10 Service That Averages Results of the Answer Service As Dependencies

interface ICompoundService
{
  double AverageAnswer { get; }
}
class CompoundService : ICompoundService, IAsyncInitialization
{
  private readonly IUniversalAnswerService _first;
  private readonly IUniversalAnswerService _second;
  public CompoundService(IUniversalAnswerService first,
    IUniversalAnswerService second)
  {
    _first = first;
    _second = second;
    Initialization = InitializeAsync();
  }
  public Task Initialization { get; private set; }
  private async Task InitializeAsync()
  {
    await AsyncInitialization.EnsureInitializedAsync(_first, _second);
    AverageAnswer = (_first.Answer + _second.Answer) / 2.0;
  }
  public double AverageAnswer { get; private set; }
}

There are a few important takeaways to keep in mind when composing services. First, because asynchronous initialization is an implementation detail, the composed service can’t know whether any of its dependencies require asynchronous initialization. If none of the dependencies require asynchronous initialization, then neither would the compound service. But because it can’t know, the compound service must declare itself as requiring asynchronous initialization.

Don’t worry too much about the performance implications of this; there will be some extra memory allocations for the asynchronous structures, but the thread will not behave asynchronously. Await has a “fast path” optimization that comes into play whenever code awaits a task that’s already complete. If the dependencies of a compound service don’t require asynchronous initialization, the sequence passed to Task.WhenAll is empty, causing Task.WhenAll to return an already-completed task. When that task is awaited by CompoundService.InitializeAsync, it won’t yield execution because the task has already completed. In this scenario, InitializeAsync completes synchronously, before the constructor completes.

A second takeaway is that it’s important to initialize all dependencies before the compound InitializeAsync returns. This ensures the compound type’s initialization is fully complete. Also, error handling is natural—if a dependent service has an initialization error, those errors propagate up from EnsureInitializedAsync, causing the compound type’s InitializeAsync to fail with the same error.

The final takeaway is that the compound service is not a special kind of type. It’s just a service that supports asynchronous initialization, just like any other kind of service. Any of these services can be mocked for testing, whether they support asynchronous initialization or not.

Wrapping Up

The patterns in this article can apply to any type of application; I’ve used them in ASP.NET and console, as well as MVVM applications. My own favorite pattern for asynchronous construction is the asynchronous factory method; it’s very simple and can’t be abused by consuming code because it never exposes an uninitialized instance. However, I’ve also found the asynchronous initialization pattern quite useful when working in scenarios where I can’t (or don’t want to) create my own instances. The AsyncLazy<T> pattern also has its place, when there are shared resources that require asynchronous initialization.

The asynchronous service patterns are more established than the MVVM patterns I introduced earlier in this series. The pattern for asynchronous data binding and the various approaches for asynchronous commands are both fairly new, and they certainly have room for improvement. The asynchronous service patterns, in contrast, have been used more widely. However, the usual caveats apply: These patterns are not gospel; they’re just techniques I’ve found useful and wanted to share. If you can improve on them or tailor them to your application’s needs, please, go right ahead! I hope these articles have been helpful to introduce you to asynchronous MVVM patterns, and, even more, that they’ve encouraged you to extend them and explore your own asynchronous patterns for UIs.


Stephen Cleary is a husband, father and programmer living in northern Michigan. He has worked with multithreading and asynchronous programming for 16 years and has used async support in the Microsoft .NET Framework since the first CTP. His homepage, including his blog, is at stephencleary.com.

Thanks to the following Microsoft technical experts for reviewing this article: James McCaffrey and Stephen Toub

 

Rate: