Running an async function synchronously Sometimes I have the need to call an async function from a non-async function and get the result back synchronously. Therefore I wrote the following helper function to be able to do this in one line.

public static T RunSync&lt;T&gt;(Func&lt;Task&lt;T&gt;&gt; taskConstructor)
{
    var signal = new ManualResetEventSlim();
    T result;
    Exception ex = null;
    ThreadPool.QueueUserWorkItem(async () =&gt;
    {
        try
        {
            var task = taskConstructor();
            result = await task.ConfigureAwait(false);
        }
        catch (Exception iex)
        {
            ex = iex;
        }
        finally
        {
            signal.Set();
        }

    });
    signal.Wait();
    if (ex != null)
        throw ex;
    return result;
}


Is this ok to do or will it behave unexpectedly in some edge cases? I know that writing this kind of async functions in can be tricky and can easily deadlock. That's why I ran it inside a ThreadPool thread which should prevent any kind of deadlock.

I think that this is probably not the most performant way to do it, but preventing deadlocks is more important in my case.

I know that re-throwing an exception is not ideal, but I think this is a compromise I have to make here.
public static class TaskExtensions
{
    private static readonly TaskFactory TaskFactory = new TaskFactory(
            CancellationToken.None, 
            TaskCreationOptions.None, 
            TaskContinuationOptions.None, 
            TaskScheduler.Default);

    public static TResult RunSync&lt;TResult&gt;(this Func&lt;Task&lt;TResult&gt;&gt; asyncFunc)
        =&gt; TaskFactory
            .StartNew(asyncFunc)
            .Unwrap()
            .GetAwaiter()
            .GetResult();

    public static void RunSync(this Func&lt;Task&gt; asyncAction)
        =&gt; TaskFactory
            .StartNew(asyncAction)
            .Unwrap()
            .GetAwaiter()
            .GetResult();
}


There are several things that worth mentioning:  


Async methods were designed to be used all the way. So, if you call an async I/O operation in the bottom layer then it should be be called in an async fashion till the top layer.
Async operations are sensitive for Exceptions. They can behave differently based on how you call them. (They can be swallowed, thrown as an AggregateException or thrown normally. Here the UnWrap + GetAwaiter do the magic for us to be able to handle the exception normally.  
In order to avoid deadlocks the async operation is passed to an other Task, that is where TaskFactory.StartNew comes into play.