Functional-Friendly OOP - Concurrency in C# Cookbook (2014)

Concurrency in C# Cookbook (2014)

Chapter 10. Functional-Friendly OOP

Modern programs require asynchronous programming; these days servers must scale better than ever, and end-user applications must be more reponsive than ever. Developers are finding that they must learn asynchronous programming, and as they explore this world, they find that it often clashes with the traditional object-oriented programming that they’re accustomed to.

The core reason for this is because asynchronous programming is functional. By “functional,” I don’t mean, “it works”; I mean it’s a functional style of programming instead of an procedural style of programming. A lot of developers learned basic functional programming in college and have hardly touched it since. If code like (car (cdr '(3 5 7))) gives you a chill as repressed memories come flooding back, then you may be in that category. But don’t fear; modern asynchronous programming is not that hard once you get used to it.

The major breakthrough with async is that you can still think procedurally while programming asynchronously. This makes asynchronous methods easier to write and understand. However, under the covers, asynchronous code is still functional in nature, and this causes some problems when people try to force async methods into classical object-oriented designs. The recipes in this chapter deal with those friction points where asynchronous code clashes with object-oriented programming.

These friction points are especially noticeable when translating an existing OOP code base into an async-friendly code base.

10.1. Async Interfaces and Inheritance

Problem

You have a method in your interface or base class that you want to make asynchronous.

Solution

The key to understanding this problem and its solution is to realize that async is an implementation detail. It is not possible to mark interface methods or abstract methods as async. However, you can define a method with the same signature as an async method, just without the asynckeyword.

Remember that types are awaitable, not methods. You can await a Task returned by a method, whether or not that method is actually async. So, an interface or abstract method can just return a Task (or Task<T>), and the return value of that method is awaitable.

The following code defines an interface with an asynchronous method (without the async keyword), an implementation of that interface (with async), and an independent method that consumes a method of the interface (via await):

interface IMyAsyncInterface

{

Task<int> CountBytesAsync(string url);

}

class MyAsyncClass : IMyAsyncInterface

{

public async Task<int> CountBytesAsync(string url)

{

var client = new HttpClient();

var bytes = await client.GetByteArrayAsync(url);

return bytes.Length;

}

}

static async Task UseMyInterfaceAsync(IMyAsyncInterface service)

{

var result = await service.CountBytesAsync("http://www.example.com");

Trace.WriteLine(result);

}

This same pattern works for abstract methods in base classes.

An asynchronous method signature only means that the implementation may be asynchronous. It is possible for the actual implementation to be synchronous if it has no real asynchronous work to do. For example, a test stub may implement the same interface (without async) by using something like FromResult:

class MyAsyncClassStub : IMyAsyncInterface

{

public Task<int> CountBytesAsync(string url)

{

return Task.FromResult(13);

}

}

Discussion

At the time of this writing (2014), async and await are still pretty new. As asynchronous methods become more common, asynchronous methods on interfaces and base classes will become more common as well. They’re not that hard to work with if you keep in mind that it is the return type that is awaitable (not the method) and that an asynchronous method definition may be implemented either asynchronously or synchronously.

See Also

Recipe 2.2 covers returning a completed task, implementing an asynchronous method signature with synchrononus code.

10.2. Async Construction: Factories

Problem

You are coding a type that requires some asynchronous work to be done in its constructor.

Solution

Constructors cannot be async, nor can they use the await keyword. It would certainly be useful to await in a constructor, but this would change the C# language considerably.

One possibility is to have a constructor paired with an async initialization method, so the type could be used like this:

var instance = new MyAsyncClass();

await instance.InitializeAsync();

However, there are disadvantages to this approach. It can be easy to forget to call the InitializeAsync method, and the instance is not usable immediately after it was constructed.

A better solution is to make the type its own factory. The following type illustrates the asynchronous factory method pattern:

class MyAsyncClass

{

private MyAsyncClass()

{

}

private async Task<MyAsyncClass> InitializeAsync()

{

await Task.Delay(TimeSpan.FromSeconds(1));

return this;

}

public static Task<MyAsyncClass> CreateAsync()

{

var result = new MyAsyncClass();

return result.InitializeAsync();

}

}

The constructor and InitializeAsync method are private so that other code cannot possibly misuse them; the only way to create an instance is via the static CreateAsync factory method, and calling code cannot access the instance until after the initialization is complete.

Other code can create an instance like this:

var instance = await MyAsyncClass.CreateAsync();

Discussion

The primary advantage of this pattern is that there is no way that other code can get an uninitialized instance of MyAsyncClass. That’s why I prefer this pattern over other approaches whenever I can use it.

Unfortunately, this approach does not work in some scenarios—in particular, when your code is using a Dependency Injection provider. As of this writing (2014), no major Dependency Injection or Inversion of Control library works with async code. There are a couple of alternatives that you can consider in this case.

If the instance you’re creating is actually a shared resource, then you can use the asynchronous lazy type discussed in Recipe 13.1. Otherwise, you can use the asynchronous initialization pattern discussed in Recipe 10.3.

Here’s an example of what not to do:

class MyAsyncClass

{

public MyAsyncClass()

{

InitializeAsync();

}

// BAD CODE!!

private async void InitializeAsync()

{

await Task.Delay(TimeSpan.FromSeconds(1));

}

}

At first glance, this seems like a reasonable approach: you get a regular constructor that kicks off an asynchronous operation; however, there are several drawbacks that are due to the use of async void. The first problem is that when the constructor completes, the instance is still being asynchronously initialized, and there isn’t an obvious way to determine when the asynchronous initialization has completed. The second problem is with error handling: any exceptions raised from InitializeAsync can’t be caught by any catch clauses surrounding the object construction.

See Also

Recipe 10.3 covers the asynchronous initilization pattern, a way of doing asynchronous construction that works with Dependency Injection/Inversion of Control containers.

Recipe 13.1 covers asynchronous lazy initialization, which is a viable solution if the instance is conceptually a shared resource or service.

10.3. Async Construction: The Asynchronous Initialization Pattern

Problem

You are coding a type that requires some asynchronous work to be done in its constructor, but you cannot use the asynchronous factory pattern (Recipe 10.2) because the instance is created via reflection (e.g., a Dependency Injection/Inversion of Control library, data binding,Activator.CreateInstance, etc.).

Solution

When you have this scenario, you have to return an uninitialized instance, but you can mitigate this by applying a common pattern: the asynchronous initialization pattern. Every type that requires asynchronous initialization should define a property as such:

Task Initialization { get; }

I usually like to define this in a marker interface for types that require asynchronous initialization:

/// <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; }

}

When you implement this pattern, you should start the initialization (and assign the Initialization property) in the constructor. The results of the asynchronous initialization (including any exceptions) are exposed via that Initialization property. Here’s an example implementation of a simple type using asynchronous initialization:

class MyFundamentalType : IMyFundamentalType, IAsyncInitialization

{

public MyFundamentalType()

{

Initialization = InitializeAsync();

}

public Task Initialization { get; private set; }

private async Task InitializeAsync()

{

// Asynchronously initialize this instance.

await Task.Delay(TimeSpan.FromSeconds(1));

}

}

If you are using a Dependency Injection/Inversion of Control library, you can create and initialize an instance of this type using code like this:

IMyFundamentalType instance = UltimateDIFactory.Create<IMyFundamentalType>();

var instanceAsyncInit = instance as IAsyncInitialization;

if (instanceAsyncInit != null)

await instanceAsyncInit.Initialization;

We can extend this pattern to allow composition of types with asynchronous initialization. The following example defines another type that depends on an IMyFundamentalType that we defined above:

class MyComposedType : IMyComposedType, IAsyncInitialization

{

private readonly IMyFundamentalType _fundamental;

public MyComposedType(IMyFundamentalType fundamental)

{

_fundamental = fundamental;

Initialization = InitializeAsync();

}

public Task Initialization { get; private set; }

private async Task InitializeAsync()

{

// Asynchronously wait for the fundamental instance to initialize,

// if necessary.

var fundamentalAsyncInit = _fundamental as IAsyncInitialization;

if (fundamentalAsyncInit != null)

await fundamentalAsyncInit.Initialization;

// Do our own initialization (synchronous or asynchronous).

...

}

}

The composed type waits for all of its components to initialize before it proceeds with its initialization. The rule to follow is that every component should be initialized by the end of InitializeAsync. This ensures that all dependent types are initialized as part of the composed initialization. Any exceptions from a component initialization are propagated to the composed type’s initialization.

Discussion

If you can, I recommend using asynchronous factories (Recipe 10.2) or asynchronous lazy initialization (Recipe 13.1) instead of this solution. Those are the best approaches because you never expose an uninitialized instance. However, if your instances are created by Dependency Injection/Inversion of Control, data binding, etc., then you are forced to expose an uninitialized instance, and in that case I recommend using the asynchronous initialization pattern in this recipe.

Remember from when we looked at asynchronous interfaces (Recipe 10.1) that an asynchronous method signature only means that the method may be asynchronous. The MyComposedType.InitializeAsync code above is a good example of this: if the IMyFundamentalType instance does not also implement IAsyncInitialization and MyComposedType has no asynchronous initialization of its own, then its InitializeAsync method will actually complete synchronously.

The code for checking whether an instance implements IAsyncInitialization and initializing it is a bit awkward, and it becomes more so when you have a composed type that depends on a larger number of components. It’s easy enough to create a helper method that can be used to simplify the code:

public static class AsyncInitialization

{

static Task WhenAllInitializedAsync(params object[] instances)

{

return Task.WhenAll(instances

.OfType<IAsyncInitialization>()

.Select(x => x.Initialization));

}

}

You can call InitializeAllAsync and pass in whatever instances you want initialized; the method will ignore any instances that do not implement IAsyncInitialization. The initialization code for a composed type that depends on three injected instances can then look like this:

private async Task InitializeAsync()

{

// Asynchronously wait for all 3 instances to initialize, if necessary.

await AsyncInitialization.WhenAllInitializedAsync(_fundamental,

_anotherType, _yetAnother);

// Do our own initialization (synchronous or asynchronous).

...

}

See Also

Recipe 10.2 covers asynchronous factories, which are a way to do asynchronous construction without exposing uninitialized instances.

Recipe 13.1 covers asynchronous lazy initialization, which can be used if the instance is a shared resource or service.

Recipe 10.1 covers asynchronous interfaces.

10.4. Async Properties

Problem

You have a property that you want to make async. The property is not used in data binding.

Solution

This is a problem that often comes up when converting existing code to use async; in this situation, you have a property whose getter invokes a method that is now asynchronous. However, there is no such thing as an “asynchronous property.” It’s not possible to use the async keyword with a property, and that’s a good thing. Property getters should return current values; they should not be kicking off background operations:

// What we think we want (does not compile).

public int Data

{

async get

{

await Task.Delay(TimeSpan.FromSeconds(1));

return 13;

}

}

When you find that your code wants an “asynchronous property,” what your code really needs is something a little different. The solution depends on whether your property value needs to be evaluated once or multiple times; you have a choice between these semantics:

§ A value that is asynchronously evaluated each time it is read

§ A value that is asynchronously evaluated once and is cached for future access

If your “asynchronous property” needs to kick off a new (asynchronous) evaluation each time it is read, then it is not a property. It is actually a method in disguise. If you encountered this situation when converting synchronous code to asynchronous, then it’s time to admit that the original design was actually incorrect; the property really should have been a method all along:

// As an asynchronous method.

public async Task<int> GetDataAsync()

{

await Task.Delay(TimeSpan.FromSeconds(1));

return 13;

}

It is possible to return a Task<int> directly from a property, like this:

// As a Task-returning property.

// This API design is questionable.

public Task<int> Data

{

get { return GetDataAsync(); }

}

private async Task<int> GetDataAsync()

{

await Task.Delay(TimeSpan.FromSeconds(1));

return 13;

}

However, I do not recommend this approach. If every access to a property is going to kick off a new asynchronous operation, then that “property” should really be a method. The fact that it’s an asynchronous method makes it clearer that a new asynchronous operation is initiated every time, so the API is not misleading. Recipe 10.3 and Recipe 10.6 do use task-returning properties, but those properties apply to the instance as a whole; they do not start a new asynchronous operation every time they are read.

The preceding solution covers the scenario where the property value is evaluated every time it is retrieved. The other scenario is that the “asynchronous property” should only kick off a single (asynchronous) evaluation and that the resulting value should be cached for future use. In this case, you can use asynchronous lazy initialization. We’ll cover this in detail in Recipe 13.1, but in the meantime, here’s an example of what the code would look like:

// As a cached value.

public AsyncLazy<int> Data

{

get { return _data; }

}

private readonly AsyncLazy<int> _data =

new AsyncLazy<int>(async () =>

{

await Task.Delay(TimeSpan.FromSeconds(1));

return 13;

});

The code will only execute the asynchronous evaluation once and then return that same value to all callers. Calling code looks like this:

int value = await instance.Data;

In this case, the property syntax is appropriate since there is only one evaluation happening.

Discussion

One of the important questions to ask yourself is whether reading the property should start a new asynchronous operation; if the answer is “yes,” then use an asynchronous method instead of a property. If the property should act as a lazy-evaluated cache, then use asynchronous intiailization (see Recipe 13.1). We didn’t cover properties that are used in data binding; that scenario will be covered in Recipe 13.3.

When you’re converting a synchronous property to an “asynchronous property,” here’s an example of what not to do:

private async Task<int> GetDataAsync()

{

await Task.Delay(TimeSpan.FromSeconds(1));

return 13;

}

public int Data

{

// BAD CODE!!

get { return GetDataAsync().Result; }

}

You don’t want to use Result or Wait to force asynchronous code to be synchronous. In GUI and ASP.NET platforms, such code can easily cause deadlocks. Even if you work around the deadlocks, you would still be exposing a misleading API: a property getter (which should be a fast, synchronous operation) is actually a blocking operation. These problems with blocking are discussed in more detail in Chapter 1.

While we’re on the subject of properties in async code, it’s worth thinking about how state relates to asynchronous code. This is especially true if you’re converting a synchronous code base to asynchronous. Consider any state that you expose in your API (e.g., via properties); for each piece of state, ask yourself: what is the current state of an object that has an asynchronous operation in progress? There’s no right answer, but it’s important to think about the semantics you want and to document them.

For example, consider Stream.Position, which represents the current offset of the stream pointer. With the synchronous API, when you call Stream.Read or Stream.Write, the actual reading/writing is done and Stream.Position is updated to reflect the new position before theRead or Write method returns. The semantics are clear for synchronous code.

Now, consider Stream.ReadAsync and Stream.WriteAsync: when should Stream.Position be updated? When the read/write operation is complete, or before it actually happens? If it’s updated before the operation completes, is it updated synchronously by the timeReadAsync/WriteAsync returns, or could it happen shortly after that?

This is a great example of how a property that exposes state has perfectly clear semantics for synchronous code but no obviously correct semantics for asynchronous code. It’s not the end of the world—you just need to think about your entire API when async-enabling your types and document the semantics you choose.

See Also

Recipe 13.1 covers asynchronous lazy initialization in detail.

Recipe 13.3 covers “asynchronous properties” that need to support data binding.

10.5. Async Events

Problem

You have an event that you need to use with handlers that might be async, and you need to detect whether the event handlers have completed. Note that this is a rare situation when raising an event; usually, when you raise an event, you don’t care when the handlers complete.

Solution

It’s not feasible to detect when async void handlers have returned, so you need some alternative way to detect when the asynchronous handlers have completed. The Windows Store platform introduced a concept called deferrals that we can use to track asynchronous handlers. An asynchronous handler allocates a deferral before its first await, and later notifies the deferral when it is complete. Synchronous handlers do not need to use deferrals.

The Nito.AsyncEx library includes a type called a DeferralManager, which is used by the component raising the event. This deferral manager then permits event handlers to allocate deferrals and keeps track of when all the deferrals have completed.

For each of your events where you need to wait for the handlers to complete, you first extend your event arguments type as such:

public class MyEventArgs : EventArgs

{

private readonly DeferralManager _deferrals = new DeferralManager();

... // Your own constructors and properties.

public IDisposable GetDeferral()

{

return _deferrals.GetDeferral();

}

internal Task WaitForDeferralsAsync()

{

return _deferrals.SignalAndWaitAsync();

}

}

When you’re dealing with asynchronous event handlers, it’s best to make your event arguments type threadsafe. The easiest way to do this is to make it immutable (i.e., have all its properties be read-only).

Then, each time you raise the event, you can (asynchronously) wait for all asynchronous event handlers to complete. The following code will return a completed task if there are no handlers; otherwise, it will create a new instance of your event arguments type, pass it to the handlers, and wait for any asynchronous handlers to complete:

public event EventHandler<MyEventArgs> MyEvent;

private Task RaiseMyEventAsync()

{

var handler = MyEvent;

if (handler == null)

return Task.FromResult(0);

var args = new MyEventArgs(...);

handler(this, args);

return args.WaitForDeferralsAsync();

}

Asynchronous event handlers can then use the deferral within a using block; the deferral notifies the deferral manager when it is disposed of:

async void AsyncHandler(object sender, MyEventArgs args)

{

using (args.GetDeferral())

{

await Task.Delay(TimeSpan.FromSeconds(2));

}

}

This is slightly different than how Windows Store deferrals work. In the Windows Store API, each event that needs deferrals defines its own deferral type, and that deferral type has an explicit Complete method rather than being IDisposable.

Discussion

There are logically two different kinds of events used in .NET, with very different semantics. I call these notification events and command events to distinguish them; this is not official terminology, just some terms that I chose for clarity. A notification event is an event that is raised to notify other components of some situation. A notification is purely one-way; the sender of the event does not care whether there are any receivers of the event. With notifications, the sender and receiver can be entirely disconnected. Most events are notification events; one example is a button click.

In contrast, a command event is an event that is raised to implement some functionality on behalf of the sending component. Command events are not “events” in the true sense of the term, though they are often implemented as .NET events. The sender of a command must wait until the receiver handles it before moving on. If you use events to implement the Visitor pattern, then those are command events. Lifecycle events are also command events, so ASP.NET page lifecycle events and Windows Store events, such as Application.Suspending fall into this category. Any event that is actually an implementation is also a command event (e.g., BackgroundWorker.DoWork).

Notification events do not require any special code to allow asynchronous handlers; the event handlers can be async void and they work just fine. When the event sender raises the event, the asynchronous event handlers aren’t completed immediately, but that doesn’t matter because they’re just notification events. So, if your event is a notification event, the grand total amount of work you need to do to support asynchronous handlers is: nothing.

Command events are a different story. When you have a command event, you need a way to detect when the handlers have completed. The preceding solution with deferrals should only be used for command events.

TIP

The DeferralManager type is in the Nito.AsyncEx NuGet package.

See Also

Chapter 2 covers the basics of asynchronous programming.

10.6. Async Disposal

Problem

You have a type that allows asynchronous operations but also needs to allow disposal of its resources.

Solution

There are a couple of options for dealing with existing operations when disposing of an instance: you can either treat the disposal as a cancellation request that is applied to all existing operations, or you can implement an actual asynchronous completion.

Treating disposal as a cancellation has a historic precedence on Windows; types such as file streams and sockets cancel any existing reads or writes when they are closed. We can do something very similar in .NET by defining our own private CancellationTokenSource and passing that token to our internal operations. With this code, Dispose will cancel the operations but will not wait for those operations to complete:

class MyClass : IDisposable

{

private readonly CancellationTokenSource _disposeCts =

new CancellationTokenSource();

public async Task<int> CalculateValueAsync()

{

await Task.Delay(TimeSpan.FromSeconds(2), _disposeCts.Token);

return 13;

}

public void Dispose()

{

_disposeCts.Cancel();

}

}

The preceding code shows the basic pattern around Dispose. In a real-world app, we should also put in checks that the object is not already disposed of and also allow the user to supply her own CancellationToken (using the technique from Recipe 9.8):

public async Task<int> CalculateValueAsync(CancellationToken cancellationToken)

{

using (var combinedCts = CancellationTokenSource

.CreateLinkedTokenSource(cancellationToken, _disposeCts.Token))

{

await Task.Delay(TimeSpan.FromSeconds(2), combinedCts.Token);

return 13;

}

}

Calling code will have any existing operations canceled when Dispose is called:

async Task Test()

{

Task<int> task;

using (var resource = new MyClass())

{

task = CalculateValueAsync();

}

// Throws OperationCanceledException.

var result = await task;

}

For some types, implementing Dispose as a cancellation request works just fine (e.g., HttpClient has these semantics). However, other types need to know when all the operations have completed. For these types, you need some kind of asynchronous completion.

Asynchronous completion is very similar to asynchronous initialization (see Recipe 10.3): there isn’t much in the way of official guidance, so I’ll describe one possible pattern, which is based on how TPL Dataflow blocks work. The important parts of asynchronous completion can be wrapped up in an interface:

/// <summary>

/// Marks a type as requiring asynchronous completion and provides

/// the result of that completion.

/// </summary>

interface IAsyncCompletion

{

/// <summary>

/// Starts the completion of this instance. This is conceptually similar

/// to <see cref="IDisposable.Dispose"/>.

/// After you call this method, you should not invoke any other members of

/// this instance except <see cref="Completion"/>.

/// </summary>

void Complete();

/// <summary>

/// Gets the result of the completion of this instance.

/// </summary>

Task Completion { get; }

}

The implementing type can use code like this:

class MyClass : IAsyncCompletion

{

private readonly TaskCompletionSource<object> _completion =

new TaskCompletionSource<object>();

private Task _completing;

public Task Completion

{

get { return _completion.Task; }

}

public void Complete()

{

if (_completing != null)

return;

_completing = CompleteAsync();

}

private async Task CompleteAsync()

{

try

{

... // Asynchronously wait for any existing operations.

}

catch (Exception ex)

{

_completion.TrySetException(ex);

}

finally

{

_completion.TrySetResult(null);

}

}

}

Calling code is not exactly elegant; we can’t use the using statement because Dispose must be asynchronous. However, we can define a pair of helper methods that allow us to do something similar to using:

static class AsyncHelpers

{

public static async Task Using<TResource>(Func<TResource> construct,

Func<TResource, Task> process) where TResource : IAsyncCompletion

{

// Create the resource we're using.

var resource = construct();

// Use the resource, catching any exceptions.

Exception exception = null;

try

{

await process(resource);

}

catch (Exception ex)

{

exception = ex;

}

// Complete (logically dispose) the resource.

resource.Complete();

await resource.Completion;

// Re-throw the process delegate exception if necessary.

if (exception != null)

ExceptionDispatchInfo.Capture(exception).Throw();

}

public static async Task<TResult> Using<TResource, TResult>(

Func<TResource> construct, Func<TResource,

Task<TResult>> process) where TResource : IAsyncCompletion

{

// Create the resource we're using.

var resource = construct();

// Use the resource, catching any exceptions.

Exception exception = null;

TResult result = default(TResult);

try

{

result = await process(resource);

}

catch (Exception ex)

{

exception = ex;

}

// Complete (logically dispose) the resource.

resource.Complete();

try

{

await resource.Completion;

}

catch

{

// Only allow exceptions from Completion if the process

// delegate did not throw an exception.

if (exception == null)

throw;

}

// Re-throw the process delegate exception if necessary.

if (exception != null)

ExceptionDispatchInfo.Capture(exception).Throw();

return result;

}

}

The code uses ExceptionDispatchInfo to preserve the stack trace of the exception. Once these helpers are in place, calling code can use the Using method as such:

async Task Test()

{

await AsyncHelpers.Using(() => new MyClass(), async resource =>

{

// Use resource.

});

}

Discussion

Asynchronous completion is definitely more awkward than implementing Dispose as a cancellation request, and the more complex approach should only be used when you really need it. In fact, most of the time you can get away with not disposing anything at all, which is certainly the easiest approach because you don’t have to do anything.

The asynchronous completion pattern described in this recipe is used by TPL Dataflow blocks and a handful of other types (e.g., ConcurrentExclusiveSchedulerPair). Dataflow blocks also have another type of completion request indicating that they should complete with an error (IDataflowBlock.Fault(Exception)). This may make sense for your types as well, so take the IAsyncCompletion in this recipe as one example of how you can implement asynchronous completion.

This recipe has two patterns for handling disposal; it is also possible to use both of them if you want. This would give your type the semantics of a clean shutdown if the client code uses Complete and Completion or a “cancel” if the client code uses Dispose.

See Also

Recipe 10.3 covers the asynchronous initialization pattern.

The MSDN documentation for TPL Dataflow covers Dataflow Block Completion and the clean shutdown semantics of TPL Dataflow blocks.

Recipe 9.8 covers linked cancellation tokens.

Recipe 10.1 covers asynchronous interfaces.