DEV Community

Daniel J. Summers
Daniel J. Summers

Posted on • Originally published at techblog.djs-consulting.com on

A Handy C# Async Utility Method

In the course of writing C# code utilizing the new (for 4.5.1) Task-based asynchronous programming, I’ve run across a couple of places where the “await keyword either is not allowed (a catch block or a property accessor) or the “async keyword greatly complicates the syntax (lambda expressions). I’ve found myself writing this method for two different projects, and so I thought I would drop this Q&D, more-comments-than-code utility method here for others to use if you see the need.

(UPDATE: This works well in console applications; it can cause deadlocks in desktop and web apps. Test before you rely on it. FURTHER UPDATE: to get around this, add .ConfigureAwait(false) after the Task.WaitAll call.)

/// <summary>
/// Get the result of a task in contexts where the "await" keyword may be prohibited
/// </summary>
/// <typeparam name="T">The return type for the task</typeparam>
/// <param name="task">The task to be awaited</param>
/// <returns>The result of the task</returns>
public static T TaskResult<T>(Task<T> task)
{
    Task.WaitAll(task);
    return task.Result;
}
Enter fullscreen mode Exit fullscreen mode

And, in places where you can’t do something like this…

/// <summary>
/// A horribly contrived example class
/// </summary>
/// <remarks>Don't ever structure your POCOs this way, unless EF is handling the navigation properties</remarks>
public class ExampleClass
{
    /// <summary>
    /// A contrived ID to a dependent entity
    /// </summary>
    public int ForeignKeyID { get; set; }

    /// <summary>
    /// The contrived dependent entity
    /// </summary>
    public DependentEntity DependentEntity
    {
        get
        {
            // Does not compile; can't use await without async, can't mark a property as async
            return await Data.DependentEntities
                .FirstOrDefaultAsync(entity => entity.ID == ForeignKeyID);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

…you can instead do this in that “DependentEntity property…

    /// <summary>
    /// The contrived dependent entity
    /// </summary>
    public DependentEntity DependentEntity
    {
        get
        {
            return UtilClass.TaskResult<DependentEntity>(Data.DependentEntities
                .FirstOrDefaultAsync(entity => entity.ID == ForeignKeyID));
        }
    }
Enter fullscreen mode Exit fullscreen mode

(UPDATE on dev.to post [4 Aug 2017]: I've learned much regarding C# and async/await. If your external dependency defines a non-async API, use it instead of wrapping it with this.)

This post was originally published on techblog.djs-consulting.com

Top comments (0)