We designed the Stormpath .NET SDK with asynchrony in mind. Since the goal of the SDK is to make network calls to the Stormpath API, it’s a great fit for the Task-based asynchrony pattern introduced in .NET 4.5. Every network method returns a Task<T>, which can be awaited to get the result.

Native support for Tasks in ASP.NET and ASP.NET Core means that your application can intelligently pause threads that are waiting on asynchronous operations, which increases performance.

Embracing the Task pattern in the SDK has the side benefit of making it clear when and where network access will occur in your code: if a method doesn’t return a Task, it won’t make a network call. Nice and readable, just like it should be.

However, using Tasks in a library leads to a problem: what happens when your consuming code can’t use await?

The problem of blocking

It’s possible to synchronously block on an asynchronous Task by calling task.Result or task.Wait(). However, it’s a really bad idea. In a web application, it can lead to deadlocks. Don’t do it!

The await keyword provides a way to wait for a Task without actually blocking, using compiler-generated magic continuations. This requires you to mark the method body as async. In most cases, this is the perfect solution. The only problem areas are:

  • Existing applications that can’t use async without significant refactoring of existing code.
  • Methods that cannot be marked as async, like void Main() or OWIN Startup methods.
  • These edge cases don’t happen often. However, when they do, the library experience is poor: the developer is forced to use a bad pattern (blocking) without any other option.

    To provide a solution for situations where the SDK needs to operate synchronously, we decided to implement every relevant SDK method twice — once as an asynchronous method, and once as a (natively) synchronous method. We were inspired by StackExchange’s Dapper library, where they call it “dual-stack design”. Entity Framework 6 and later also uses this pattern.

    For example, on the IApplication interface, there are two methods that represent the same operation:

    Providing two versions of each method solves one problem, but introduces another: now the interfaces are bloated with similar-looking methods, which could be confusing for a newcomer. (Should I use CreateAccount or CreateAccountAsync? Why are there two?)

    I’m a big believer that SDKs should guide developers toward best practices whenever possible. Using the asynchronous method is a best practice, but a synchronous method sitting on the interface is so tempting! What if the synchronous methods were only visible when you needed them?

    Hiding methods behind a namespace

    To create an “opt-in” experience for the Stormpath SDK’s synchronous methods, we used C# extension methods to implement a mixin pattern and hide the methods behind the Stormpath.SDK.Sync namespace.

    Now, instead of both methods living on the interface as shown above, the synchronous method lives in an extension class:

    Now the synchronous “overloads” are only available if the developer imports the Stormpath.SDK.Sync namespace at the top of their code file. Otherwise, they aren’t visible.

    Why our solution?

    I like the solution that we used in the Stormpath .NET SDK because it:

  • Suggests async best practices by default
  • Supports the edge cases where asynchrony isn’t available
  • Exposes additional behavior in an intuitive way
  • If you have any thoughts or critiques, share them with me on twitter or below in the comments! And, if you’re interested in learning more about the Stormpath .NET SDK, you can check out these resources:

  • The .NET SDK Documentation
  • Simple Social Login in ASP.NET Core
  • 10 Minutes to User Authentication in ASP.NET