I am learning about async/await, and ran into a situation where I need to call an async method synchronously. How can I do that?
Async method:
public async Task<Customers> GetCustomers()
{
return await Service.GetCustomersAsync();
}
Normal usage:
public async void GetCustomers()
{
customerList = await GetCustomers();
}
I've tried using the following:
Task<Customer> task = GetCustomers();
task.Wait()
Task<Customer> task = GetCustomers();
task.RunSynchronously();
Task<Customer> task = GetCustomers();
while(task.Status != TaskStatus.RanToCompletion)
I also tried a suggestion from here, however it doesn't work when the dispatcher is in a suspended state.
public static void WaitWithPumping(this Task task)
{
if (task == null) throw new ArgumentNullException(“task”);
var nestedFrame = new DispatcherFrame();
task.ContinueWith(_ => nestedFrame.Continue = false);
Dispatcher.PushFrame(nestedFrame);
task.Wait();
}
Here is the exception and stack trace from calling RunSynchronously
:
System.InvalidOperationException Message: RunSynchronously may not be called on a task unbound to a delegate. InnerException: null Source: mscorlib StackTrace:
at System.Threading.Tasks.Task.InternalRunSynchronously(TaskScheduler scheduler)
at System.Threading.Tasks.Task.RunSynchronously()
at MyApplication.CustomControls.Controls.MyCustomControl.CreateAvailablePanelList() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 638
at MyApplication.CustomControls.Controls.MyCustomControl.get_AvailablePanels() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 233
at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>b__36(DesktopPanel panel) in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 597
at System.Collections.Generic.List`1.ForEach(Action`1 action)
at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>d__3b.MoveNext() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 625
at System.Runtime.CompilerServices.TaskAwaiter.<>c__DisplayClass7.<TrySetContinuationForAwait>b__1(Object state)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at MyApplication.App.Main() in C:\Documents and Settings\...\MyApplication\obj\Debug\App.g.cs:line 50
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Task
synchronously; 3) I'm integrating GeneXus with MongoDB C# driver, which expose some methods only asynchronously
await
within synchronised blocks. Should I have Microsoft change their language? Or should I drop my synchronisation and accept messed up data structures? async
is that cancer, not so much GPL. Once you have it you can't get rid of it.
Here's a workaround I found that works for all cases (including suspended dispatchers). It's not my code and I'm still working to fully understand it, but it does work.
It can be called using:
customerList = AsyncHelpers.RunSync<List<Customer>>(() => GetCustomers());
Code is from here
public static class AsyncHelpers
{
/// <summary>
/// Execute's an async Task<T> method which has a void return value synchronously
/// </summary>
/// <param name="task">Task<T> method to execute</param>
public static void RunSync(Func<Task> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
synch.Post(async _ =>
{
try
{
await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
}
/// <summary>
/// Execute's an async Task<T> method which has a T return type synchronously
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="task">Task<T> method to execute</param>
/// <returns></returns>
public static T RunSync<T>(Func<Task<T>> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
T ret = default(T);
synch.Post(async _ =>
{
try
{
ret = await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
return ret;
}
private class ExclusiveSynchronizationContext : SynchronizationContext
{
private bool done;
public Exception InnerException { get; set; }
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
readonly Queue<Tuple<SendOrPostCallback, object>> items =
new Queue<Tuple<SendOrPostCallback, object>>();
public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("We cannot send to our same thread");
}
public override void Post(SendOrPostCallback d, object state)
{
lock (items)
{
items.Enqueue(Tuple.Create(d, state));
}
workItemsWaiting.Set();
}
public void EndMessageLoop()
{
Post(_ => done = true, null);
}
public void BeginMessageLoop()
{
while (!done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (items)
{
if (items.Count > 0)
{
task = items.Dequeue();
}
}
if (task != null)
{
task.Item1(task.Item2);
if (InnerException != null) // the method threw an exeption
{
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
}
}
else
{
workItemsWaiting.WaitOne();
}
}
}
public override SynchronizationContext CreateCopy()
{
return this;
}
}
}
Be advised this answer is three years old. I wrote it based mostly on a experience with .Net 4.0, and very little with 4.5 especially with async-await
. Generally speaking it's a nice simple solution, but it sometimes breaks things. Please read the discussion in the comments.
.Net 4.5
Just use this:
// For Task<T>: will block until the task is completed...
var result = task.Result;
// For Task (not Task<T>): will block until the task is completed...
task2.RunSynchronously();
See: TaskAwaiter, Task.Result, Task.RunSynchronously
.Net 4.0
Use this:
var x = (IAsyncResult)task;
task.Start();
x.AsyncWaitHandle.WaitOne();
...or this:
task.Start();
task.Wait();
.Result
can produce a deadlock in certain scenario's
Result
can easily cause deadlock in async
code, as I describe on my blog.
Surprised no one mentioned this:
public Task<int> BlahAsync()
{
// ...
}
int result = BlahAsync().GetAwaiter().GetResult();
Not as pretty as some of the other methods here, but it has the following benefits:
it doesn't swallow exceptions (like Wait)
it won't wrap any exceptions thrown in an AggregateException (like Result)
works for both Task and Task
Also, since GetAwaiter
is duck-typed, this should work for any object that is returned from an async method (like ConfiguredAwaitable
or YieldAwaitable
), not just Tasks.
edit: Please note that it's possible for this approach (or using .Result
) to deadlock, unless you make sure to add .ConfigureAwait(false)
every time you await, for all async methods that can possibly be reached from BlahAsync()
(not just ones it calls directly). Explanation.
// In BlahAsync() body
await FooAsync(); // BAD!
await FooAsync().ConfigureAwait(false); // Good... but make sure FooAsync() and
// all its descendants use ConfigureAwait(false)
// too. Then you can be sure that
// BlahAsync().GetAwaiter().GetResult()
// won't deadlock.
If you're too lazy to add .ConfigureAwait(false)
everywhere, and you don't care about performance you can alternatively do
Task.Run(() => BlahAsync()).GetAwaiter().GetResult()
GetAwaiter()
, "This method is intended for compiler user rather than use directly in code."
It's much simpler to run the task on the thread pool, rather than trying to trick the scheduler to run it synchronously. That way you can be sure that it won't deadlock. Performance is affected because of the context switch.
Task<MyResult> DoSomethingAsync() { ... }
// Starts the asynchronous task on a thread-pool thread.
// Returns a proxy to the original task.
Task<MyResult> task = Task.Run(() => DoSomethingAsync());
// Will block until the task is completed...
MyResult result = task.Result;
Task.Run(DoSomethingAsync)
instead? This removes one level of delegates.
Task<MyResult> task = Task.Run(async () => await DoSomethingAsync());
is more explicit and addresses the concern by @sgnsajgon that it might be returning a Task<Task<MyResult>>. The correct overload of Task.Run is selected either way, but the async delegate makes your intent obvious.
I'm learning about async/await, and ran into a situation where I need to call an async method synchronously. How can I do that?
The best answer is you don't, with the details dependent on what the "situation" is.
Is it a property getter/setter? In most cases, it's better to have asynchronous methods than "asynchronous properties". (For more info, see my blog post on asynchronous properties).
Is this an MVVM app and you want to do asynchronous data binding? Then use something like my NotifyTask
, as described in my MSDN article on asynchronous data binding.
Is it a constructor? Then you probably want to consider an asynchronous factory method. (For more info, see my blog post on asynchronous constructors).
There's almost always a better answer than to do sync-over-async.
If it's not possible for your situation (and you know this by asking a question here describing the situation), then I'd recommend just using synchronous code. Async all the way is best; sync all the way is second-best. Sync-over-async is not recommended.
However, there are a handful of situations where sync-over-async is necessary. Specifically, you are constrained by the calling code so that you have to be sync (and have absolutely no way to re-think or re-structure your code to allow asynchrony), and you have to call async code. This is a very rare situation, but it does come up from time to time.
In that case, you would need to use one of the hacks described in my article on brownfield async
development, specifically:
Blocking (e.g., GetAwaiter().GetResult()). Note that this can cause deadlocks (as I describe on my blog).
Running the code on a thread pool thread (e.g., Task.Run(..).GetAwaiter().GetResult()). Note that this will only work if the asynchronous code can be run on a thread pool thread (i.e., is not dependent on a UI or ASP.NET context).
Nested message loops. Note that this will only work if the asynchronous code only assumes a single-threaded context, not a specific context type (a lot of UI and ASP.NET code expect a specific context).
Nested message loops are the most dangerous of all the hacks, because it causes re-entrancy. Re-entrancy is extremely tricky to reason about, and (IMO) is the cause of most application bugs on Windows. In particular, if you're on the UI thread and you block on a work queue (waiting for the async work to complete), then the CLR actually does some message pumping for you - it'll actually handle some Win32 messages from within your code. Oh, and you have no idea which messages - when Chris Brumme says "Wouldn’t it be great to know exactly what will get pumped? Unfortunately, pumping is a black art which is beyond mortal comprehension.", then we really have no hope of knowing.
So, when you block like this on a UI thread, you're asking for trouble. Another cbrumme quote from the same article: "From time to time, customers inside or outside the company discover that we are pumping messages during managed blocking on an STA [UI thread]. This is a legitimate concern, because they know that it’s very hard to write code that’s robust in the face of reentrancy."
Yes, it is. Very hard to write code that's robust in the face of reentrancy. And nested message loops force you to write code that's robust in the face of reentrancy. This is why the accepted (and most-upvoted) answer for this question is extremely dangerous in practice.
If you are completely out of all other options - you can't redesign your code, you can't restructure it to be async - you are forced by unchangeable calling code to be sync - you can't change the downstream code to be sync - you can't block - you can't run the async code on a separate thread - then and only then should you consider embracing reentrancy.
If you do find yourself in this corner, I would recommend using something like Dispatcher.PushFrame
for WPF apps, looping with Application.DoEvents
for WinForm apps, and for the general case, my own AsyncContext.Run
.
Main()
method doesn't compile; at some point you've got to bridge the gap between the sync and async worlds. It's not a "very rare situation", it's necessary in literally every program that calls an async method. There is no option to not "do sync-over-async", just an option to shunt that burden up to the calling method instead of shouldering it in the one you're currently writing.
Main
method of console apps. ASP.NET, unit test frameworks, and every UI system all support async natively. Even if all your apps are console apps, you'd only need to do sync-over-async once per app. (of course, library callbacks that don't support async yet may require additional hacks).
async
on all of the methods in my application now. And that's a lot. Can't this just be the default?
If I am reading your question right - the code that wants the synchronous call to an async method is executing on a suspended dispatcher thread. And you want to actually synchronously block that thread until the async method is completed.
Async methods in C# 5 are powered by effectively chopping the method into pieces under the hood, and returning a Task
that can track the overall completion of the whole shabang. However, how the chopped up methods execute can depend on the type of the expression passed to the await
operator.
Most of the time, you'll be using await
on an expression of type Task
. Task's implementation of the await
pattern is "smart" in that it defers to the SynchronizationContext
, which basically causes the following to happen:
If the thread entering the await is on a Dispatcher or WinForms message loop thread, it ensures that the chunks of the async method occurs as part of the processing of the message queue. If the thread entering the await is on a thread pool thread, then the remaining chunks of the async method occur anywhere on the thread pool.
That's why you're probably running into problems - the async method implementation is trying to run the rest on the Dispatcher - even though it's suspended.
.... backing up! ....
I have to ask the question, why are you trying to synchronously block on an async method? Doing so would defeat the purpose on why the method wanted to be called asynchronously. In general, when you start using await
on a Dispatcher or UI method, you will want to turn your entire UI flow async. For example, if your callstack was something like the following:
[Top] WebRequest.GetResponse() YourCode.HelperMethod() YourCode.AnotherMethod() YourCode.EventHandlerMethod() [UI Code].Plumbing() - WPF or WinForms Code [Message Loop] - WPF or WinForms Message Loop
Then once the code has been transformed to use async, you'll typically end up with
[Top] WebRequest.GetResponseAsync() YourCode.HelperMethodAsync() YourCode.AnotherMethodAsync() YourCode.EventHandlerMethodAsync() [UI Code].Plumbing() - WPF or WinForms Code [Message Loop] - WPF or WinForms Message Loop
Actually Answering
The AsyncHelpers class above actually works because it behaves like a nested message loop, but it installs its own parallel mechanic to the Dispatcher rather than trying to execute on the Dispatcher itself. That's one workaround for your problem.
Another workaround is to execute your async method on a threadpool thread, and then wait for it to complete. Doing so is easy - you can do it with the following snippet:
var customerList = TaskEx.RunEx(GetCustomers).Result;
The final API will be Task.Run(...), but with the CTP you'll need the Ex suffixes (explanation here).
TaskEx.RunEx(GetCustomers).Result
hangs the application when it gets run on a suspended dispatcher thread. Also, the GetCustomers() method is normally run async, however in one situation it needs to run synchronously, so I was looking for a way to do that without building a sync version of the method.
async
methods; nested loops should certainly be avoided.
This is working well for me
public static class TaskHelper
{
public static void RunTaskSynchronously(this Task t)
{
var task = Task.Run(async () => await t);
task.Wait();
}
public static T RunTaskSynchronously<T>(this Task<T> t)
{
T res = default(T);
var task = Task.Run(async () => res = await t);
task.Wait();
return res;
}
}
MyAsyncMethod().RunTaskSynchronously();
Task.Run
. In other words, in normal usages like GetFromNetworkAsync().RunTaskSynchronously()
hangs for UI apps.
Tested in .Net 4.6. It can also avoid deadlock.
For async method returning Task
.
Task DoSomeWork();
Task.Run(async () => await DoSomeWork()).Wait();
For async method returning Task<T>
Task<T> GetSomeValue();
var result = Task.Run(() => GetSomeValue()).Result;
Edit:
If the caller is running in the thread pool thread (or the caller is also in a task), it may still cause a deadlock in some situation.
Result
is perfect for the job if you want a synchronous call, and downright dangerous otherwise. There is nothing in the name Result
or in the intellisense of Result
that indicates it is a blocking call. It really should be renamed.
I've faced it a few times, mostly in unit testing or in a windows service development. Currently I always use this feature:
var runSync = Task.Factory.StartNew(new Func<Task>(async () =>
{
Trace.WriteLine("Task runSync Start");
await TaskEx.Delay(2000); // Simulates a method that returns a task and
// inside it is possible that there
// async keywords or anothers tasks
Trace.WriteLine("Task runSync Completed");
})).Unwrap();
Trace.WriteLine("Before runSync Wait");
runSync.Wait();
Trace.WriteLine("After runSync Waited");
It's simple, easy and I had no problems.
Task.Run(() => ..).Wait()
(with slight tweaks). Both should work.
I found this code at Microsoft.AspNet.Identity.Core component, and it works.
private static readonly TaskFactory _myTaskFactory = new
TaskFactory(CancellationToken.None, TaskCreationOptions.None,
TaskContinuationOptions.None, TaskScheduler.Default);
// Microsoft.AspNet.Identity.AsyncHelper
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
CultureInfo culture = CultureInfo.CurrentCulture;
return AsyncHelper._myTaskFactory.StartNew<Task<TResult>>(delegate
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func();
}).Unwrap<TResult>().GetAwaiter().GetResult();
}
The simplest way I have found to run task synchronously and without blocking UI thread is to use RunSynchronously() like:
Task t = new Task(() =>
{
//.... YOUR CODE ....
});
t.RunSynchronously();
In my case, I have an event that fires when something occurs. I dont know how many times it will occur. So, I use code above in my event, so whenever it fires, it creates a task. Tasks are executed synchronously and it works great for me. I was just surprised that it took me so long to find out of this considering how simple it is. Usually, recommendations are much more complex and error prone. This was it is simple and clean.
Just a little note - this approach:
Task<Customer> task = GetCustomers();
task.Wait()
works for WinRT.
Let me explain:
private void TestMethod()
{
Task<Customer> task = GetCustomers(); // call async method as sync and get task as result
task.Wait(); // wait executing the method
var customer = task.Result; // get's result.
Debug.WriteLine(customer.Name); //print customer name
}
public class Customer
{
public Customer()
{
new ManualResetEvent(false).WaitOne(TimeSpan.FromSeconds(5));//wait 5 second (long term operation)
}
public string Name { get; set; }
}
private Task<Customer> GetCustomers()
{
return Task.Run(() => new Customer
{
Name = "MyName"
});
}
Moreover this approach works for Windows Store solutions only!
Note: This way isn't thread safe if you call your method inside of other async method (according to comments of @Servy)
CancellationToken
for my solution.
In your code, your first wait for task to execute but you haven't started it so it waits indefinitely. Try this:
Task<Customer> task = GetCustomers();
task.RunSynchronously();
Edit:
You say that you get an exception. Please post more details, including stack trace.
Mono contains the following test case:
[Test]
public void ExecuteSynchronouslyTest ()
{
var val = 0;
Task t = new Task (() => { Thread.Sleep (100); val = 1; });
t.RunSynchronously ();
Assert.AreEqual (1, val);
}
Check if this works for you. If it does not, though very unlikely, you might have some odd build of Async CTP. If it does work, you might want to examine what exactly the compiler generates and how Task
instantiation is different from this sample.
Edit #2:
I checked with Reflector that the exception you described occurs when m_action
is null
. This is kinda odd, but I'm no expert on Async CTP. As I said, you should decompile your code and see how exactly Task
is being instantiated any how come its m_action
is null
.
RunSynchronously may not be called on a task unbound to a delegate
. Google is no help since all the results for that are in chinese...
await
keyword is used. The exception posted in my earlier comment is the exception I get, although it is one of the few that I cannot Google and find a cause or resolution for.
async
and async
keywords are nothing more than syntax sugar. Compiler generates code to create Task<Customer>
in GetCustomers()
so that's where I would look first. As for exception, you only posted exception message, which is useless without exception type and stack trace. Call exception's ToString()
method and post output in the question.
Why not create a call like:
Service.GetCustomers();
that isn't async.
NOTE: I think as best practice is not recommended to change the nature of the action if it is asynchronous the best thing is handling as it is (async all the way). In that way you can get other benefits like parallel processing / multi-threading, etc.
Seeing the other answers did not use this approach, I want to post it here as well:
var customers = GetCustomersAsync().GetAwaiter().GetResult();
use below code snip
Task.WaitAll(Task.Run(async () => await service.myAsyncMethod()));
Simply calling .Result;
or .Wait()
is a risk for deadlocks as many have said in comments. Since most of us like oneliners you can use these for .Net 4.5<
Acquiring a value via an async method:
var result = Task.Run(() => asyncGetValue()).Result;
Syncronously calling an async method
Task.Run(() => asyncMethod()).Wait();
No deadlock issues will occur due to the use of Task.Run
.
Source:
https://stackoverflow.com/a/32429753/3850405
This answer is designed for anyone who is using WPF for .NET 4.5.
If you attempt to execute Task.Run()
on the GUI thread, then task.Wait()
will hang indefinitely, if you do not have the async
keyword in your function definition.
This extension method solves the problem by checking to see if we are on the GUI thread, and if so, running the task on the WPF dispatcher thread.
This class can act as the glue between the async/await world and the non-async/await world, in situations where it is unavoidable, such as MVVM properties or dependencies on other APIs that do not use async/await.
/// <summary>
/// Intent: runs an async/await task synchronously. Designed for use with WPF.
/// Normally, under WPF, if task.Wait() is executed on the GUI thread without async
/// in the function signature, it will hang with a threading deadlock, this class
/// solves that problem.
/// </summary>
public static class TaskHelper
{
public static void MyRunTaskSynchronously(this Task task)
{
if (MyIfWpfDispatcherThread)
{
var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { await task; });
result.Wait();
if (result.Status != DispatcherOperationStatus.Completed)
{
throw new Exception("Error E99213. Task did not run to completion.");
}
}
else
{
task.Wait();
if (task.Status != TaskStatus.RanToCompletion)
{
throw new Exception("Error E33213. Task did not run to completion.");
}
}
}
public static T MyRunTaskSynchronously<T>(this Task<T> task)
{
if (MyIfWpfDispatcherThread)
{
T res = default(T);
var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { res = await task; });
result.Wait();
if (result.Status != DispatcherOperationStatus.Completed)
{
throw new Exception("Error E89213. Task did not run to completion.");
}
return res;
}
else
{
T res = default(T);
var result = Task.Run(async () => res = await task);
result.Wait();
if (result.Status != TaskStatus.RanToCompletion)
{
throw new Exception("Error E12823. Task did not run to completion.");
}
return res;
}
}
/// <summary>
/// If the task is running on the WPF dispatcher thread.
/// </summary>
public static bool MyIfWpfDispatcherThread
{
get
{
return Application.Current.Dispatcher.CheckAccess();
}
}
}
I think the following helper method could also solve the problem.
private TResult InvokeAsyncFuncSynchronously<TResult>(Func< Task<TResult>> func)
{
TResult result = default(TResult);
var autoResetEvent = new AutoResetEvent(false);
Task.Run(async () =>
{
try
{
result = await func();
}
catch (Exception exc)
{
mErrorLogger.LogError(exc.ToString());
}
finally
{
autoResetEvent.Set();
}
});
autoResetEvent.WaitOne();
return result;
}
Can be used the following way:
InvokeAsyncFuncSynchronously(Service.GetCustomersAsync);
This is works for me
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp2
{
public static class AsyncHelper
{
private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
public static void RunSync(Func<Task> func)
{
_myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
}
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
}
}
class SomeClass
{
public async Task<object> LoginAsync(object loginInfo)
{
return await Task.FromResult(0);
}
public object Login(object loginInfo)
{
return AsyncHelper.RunSync(() => LoginAsync(loginInfo));
//return this.LoginAsync(loginInfo).Result.Content;
}
}
class Program
{
static void Main(string[] args)
{
var someClass = new SomeClass();
Console.WriteLine(someClass.Login(1));
Console.ReadLine();
}
}
}
I have found that SpinWait works pretty well for this.
var task = Task.Run(()=>DoSomethingAsyncronous());
if(!SpinWait.SpinUntil(()=>task.IsComplete, TimeSpan.FromSeconds(30)))
{//Task didn't complete within 30 seconds, fail...
return false;
}
return true;
The above approach doesn't need to use .Result or .Wait(). It also lets you specify a timeout so that you're not stuck forever in case the task never completes.
I know this is an old Question, but i'll like to share my solution, may not be the best but does the job:
//Declare an Event Handler:
private event EventHandler OnThemeApply;
//..somewhere in your code..
//we 'hear' the event handler
this.OnThemeApply += (object _Sender, EventArgs _E) =>
{
//Reaches here After the Async method had finished
this.OnThemeApply = null;
};
MyAsycMethod();
private void MyAsycMethod()
{
var t = System.Threading.Tasks.Task.Factory.StartNew(delegate
{
//Do something here
Invoke((MethodInvoker)(() =>
{
if(this.OnThemeApply != null) this.OnThemeApply(null, null); //<- Calls the Event
}));
});
}
On wp8:
Wrap it:
Task GetCustomersSynchronously()
{
Task t = new Task(async () =>
{
myCustomers = await GetCustomers();
}
t.RunSynchronously();
}
Call it:
GetCustomersSynchronously();
private int GetSync()
{
try
{
ManualResetEvent mre = new ManualResetEvent(false);
int result = null;
Parallel.Invoke(async () =>
{
result = await SomeCalcAsync(5+5);
mre.Set();
});
mre.WaitOne();
return result;
}
catch (Exception)
{
return null;
}
}
Or you could just go with:
customerList = Task.Run<List<Customer>>(() => { return GetCustomers(); }).Result;
For this to compile make sure you reference extension assembly:
System.Net.Http.Formatting
Try following code it works for me:
public async void TaskSearchOnTaskList (SearchModel searchModel)
{
try
{
List<EventsTasksModel> taskSearchList = await Task.Run(
() => MakeasyncSearchRequest(searchModel),
cancelTaskSearchToken.Token);
if (cancelTaskSearchToken.IsCancellationRequested
|| string.IsNullOrEmpty(rid_agendaview_search_eventsbox.Text))
{
return;
}
if (taskSearchList == null || taskSearchList[0].result == Constants.ZERO)
{
RunOnUiThread(() => {
textViewNoMembers.Visibility = ViewStates.Visible;
taskListView.Visibility = ViewStates.Gone;
});
taskSearchRecureList = null;
return;
}
else
{
taskSearchRecureList = TaskFooterServiceLayer
.GetRecurringEvent(taskSearchList);
this.SetOnAdapter(taskSearchRecureList);
}
}
catch (Exception ex)
{
Console.WriteLine("ActivityTaskFooter -> TaskSearchOnTaskList:" + ex.Message);
}
}
Success story sharing
DynamicNodeProviderBase
base class, one cannot declare it as aasync
method. Either I had to replace with a new library, or just call a synchronous op.AspNetSynchronizationContext
, so this particular hack won't work if you're calling those APIs.