You work with latest and greatest lucky you!!. Some of us have no options but support legacy code that we cannot modify etc.. We cannot do async all the way....
So sync over async in an old asp.net mvc4 web application and following this article Brownfield Async Development and a previous post of mine
It suggests doing something like below to avoid deadlock.
public SomeStuff GetSomestuff(Whatever whatever)
{
return GetSomestuffAsync(whatever).GetAwaiter().GetResult();
}
public async Task<SomeStuff> GetSomestuffAsync(Whatever whatever)
{
// Do NOT queue a synchronization context continuation.
return myRefitHttpClient.GetSomestuff(whatever).ConfigureAwait(false);
}
My question:
I want to make 2 generic methods - ExecAsync
and ExecSync
so that I drastically reduce the code I need to write. I have the the following (removed logging etc.. )
public async Task ExecAsync<T>(
Func<Task<T>> method,
Action<T> response)
{
T result = await method.Invoke().ConfigureAwait(false);
response(result);
}
But now I want the "Sync version calling the async one" but cannot get it compile/working
public void ExecSync<T>(
Func<Task<T>> method,
Action<T> response)
{
//BELOW IS WRONG! I need to call Async and then GetAwaiter().GetResult()
//ExecAsync(()=>method, r => response = r).GetAwaiter().GetResult();
//response(r);
}
Any suggestions?
UPDATE
Find this code below : is below a decent solution for sync over async
Microsoft built an AsyncHelper
(internal) class to run Async as Sync.
The source looks like:
internal static class AsyncHelper
{
private static readonly TaskFactory _myTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static void RunSync(Func<Task> task)
{
//Storing the context
var storeContext = HttpContext.Current;
taskFactory
.StartNew(task)
.Unwrap()
.GetAwaiter()
.GetResult();
//restoring context
HttpContext.Current = storeContext;
}
public static TResult RunSync<TResult>(Func<Task<TResult>> task)
{
var storeContext = HttpContext.Current;
var result= taskFactory
.StartNew(task)
.Unwrap()
.GetAwaiter()
.GetResult();
//restoring context
HttpContext.Current = storeContext;
return result;
}
}
CodePudding user response:
cannot get it compile/working
Getting it to compile is easy enough:
public void ExecSync<T>(Func<Task<T>> method, Action<T> response)
{
ExecAsync(method, response).GetAwaiter().GetResult();
}
However, getting it working is more of a challenge.
You are asking for a generic, general-purpose sync-over-async solution. This does not exist. If it did, then articles like Brownfield Async wouldn't have been written; everyone could just use the generic solution and be done with it.
The current solution assumes that your code uses ConfigureAwait(false)
for every await
in your app. If it does, then fine.
Another solution is the thread pool hack, but that one assumes that the code can run on any arbitrary thread pool thread. On old ASP.NET code, this may not be the case; in particular code that accesses HttpContext.Current
.