Executing async function synchronously - c#

I have done a lot of search on this topic, and I read most of the posts here on this site regarding this topic, however I'm still confused and I need a straight forward answer. Here is my situation:
I have an established Winform application that I can't make it all 'async'. I'm forced now to use an external library that is all written as async functions.
In my application I have
/// <summary>
/// This function I can't change it to an 'async'
/// </summary>
public void MySyncFunction()
{
//This function is my point in my application where I have to call the
//other 'async' functions but I can't change the function itself to 'async'
try
{
//I need to call the MyAsyncDriverFunction() as if it is a synchronous function
//I need the driver function to finish execution and return before processing the code that follows it
//I also need to be able to catch any exceptions
MyAsyncDriverFunction();
//Rest of the code have to wait for the above function to return
}
catch (Exception exp)
{
//Need to be able to handle the exception thrown
//from the MyAsyncDriverFunction here.
}
}
public static async Task<IEnumerable<string>> MyAsyncDriverFunction()
{
try
{
var strCollection = await AsyncExternalLibraryFunction1();
var strCollection2 = await AsyncExternalLibraryFunction2();
return strCollection;
}
catch (Exception exp)
{
//Need to be able to catch an exception and re-throw it to the caller function
}
}
As outlined in the code, I need to be able to:
I can't change my MySyncFunction to an async
Call the "MyAsyncDriverFunction" in a sync way, where it have to wait for it to finish all its work before I process the code that follows
Be able to handle exceptions in both functions (from what I read so far this is tricky?)
I need a simple way using the standard API, I can't use any third party library (even if I wanted to)

however I'm still confused and I need a straight forward answer.
That's because there isn't a "straight-forward" answer.
The only proper solution is to make MySyncFunction asynchronous. Period. All other solutions are hacks, and there is no hack that works perfectly in all scenarios.
I go into full details in my recent MSDN article on brownfield async development, but here's the gist:
You can block with Wait() or Result. As others have noted, you can easily cause a deadlock, but this can work if the asynchronous code never resumes on its captured context.
You can push the work to a thread pool thread and then block. However, this assumes that the asynchronous work is capable of being pushed to some other arbitrary thread and that it can resume on other threads, thus possibly introducing multithreading.
You can push the work to a thread pool thread that executes a "main loop" - e.g., a dispatcher or my own AsyncContext type. This assumes the asynchronous work is capable of being pushed to another thread but removes any concerns about multithreading.
You can install a nested message loop on the main thread. This will execute the asynchronous code on the calling thread, but also introduces reentrancy, which is extremely difficult to reason about correctly.
In short, there is no one answer. Every single approach is a hack that works for different kinds of asynchronous code.

Simply calling .Result or .Wait against your async method will deadlock because you're in the context of a GUI application. See https://msdn.microsoft.com/en-us/magazine/jj991977.aspx (chapter 'Async All the Way') for a nice explanation.
The solution to your problem is not easy, but it has been described in details by Stephen Cleary: here.
So you should use the Nito.AsyncEx library (available on Nuget).
If you really can't add the library he wrote to your project, you could check the source code and use portions of it, the MIT license allows it.

Just add a .Result call at the end of the method call.
var strCollection = MyAsyncDriverFunction().Result;

I'm not sure what the experts would say, but based on the Stephen Cleary advices I end up with the following idea. Having the following class
public sealed class AsyncTask
{
public static void Run(Func<Task> asyncFunc)
{
var originalContext = SynchronizationContext.Current;
bool restoreContext = false;
try
{
if (originalContext != null && originalContext.GetType() != typeof(SynchronizationContext))
{
restoreContext = true;
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
var task = asyncFunc();
task.GetAwaiter().GetResult();
}
finally
{
if (restoreContext) SynchronizationContext.SetSynchronizationContext(originalContext);
}
}
public static TResult Run<TResult>(Func<Task<TResult>> asyncFunc)
{
var originalContext = SynchronizationContext.Current;
bool restoreContext = false;
try
{
if (originalContext != null && originalContext.GetType() != typeof(SynchronizationContext))
{
restoreContext = true;
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
var task = asyncFunc();
return task.GetAwaiter().GetResult();
}
finally
{
if (restoreContext) SynchronizationContext.SetSynchronizationContext(originalContext);
}
}
}
and use it as follows
public void MySyncFunction()
{
try
{
AsyncTask.Run(() => MyAsyncDriverFunction());
}
catch (Exception exp)
{
}
}
would do what you are asking for without deadlock. The key point is to "hide" the current synchronization context during the asynchronous task execution and force using of the default synchronization context which is known to use thread pool for Post method. Again, I'm not sure if this is good or bad idea and what side effects it could introduce, but once you asked, I'm just sharing it.

Try change "await AsyncExternalLibraryFunction1()" to "AsyncExternalLibraryFunction1().Wait()" and next to it, and remove
async for function "MyAsyncDriverFunction"

Related

Will running async code from a new thread cause a deadlock?

My understanding is that if you call async code synchronously it can cause deadlock when it needs to synchronize back to the UI thread to modify UI elements or if you need to access ASP.NET HttpContext.Current. There are workarounds to solve this problem as mentioned here:
https://learn.microsoft.com/en-us/archive/msdn-magazine/2015/july/async-programming-brownfield-async-development
How to call asynchronous method from synchronous method in C#?
I was looking at the "The Thread Pool Hack" approach from the first link but I need to call GetAwaiter().GetResult() directly from the async code which is already called from a new thread e.g:
//MyWork.DoWork must execute in a separate thread due legacy code that I can't refactor right now.
public class SomeClass {
try {
var myThread = new Thread(MyWork.DoWork);
myThread.Start();
} catch (Exception ex) {
//Handle exceptions
}
}
public class MyWork {
public static bool DoWork(){
var response = MyHttpClient.MakeRequestAsync(params)
.GetAwaiter()
.GetResult();
if(!response.Succeed){
//add logs and other stuff
}
}
}
Also my call to MyHttpClient.MakeRequestAsync is NOT using .ConfigureAwait(false); and I can't add that since the same calls can be used in other places where it may need to synchronize back to the UI context
Is it safe to call .GetAwaiter().GetResult() directly on MyHttpClient.MakeRequestAsync since I'm already starting the work in a separate thread?
Once the MyHttpClient.MakeRequestAsync resumes will it resume the work in the same thread?
Update:
I cannot let the async pattern propagate I must use existing legacy code that uses the thread class so no refactoring allowed at the moment for SomeClass.

3rd party sync method freezing the UI in .NET 4.7.2 WPF

I have a .NET 4.7.2 application using WPF MVVM. I am connecting to a robot using the provided library from the manufacturer. Unfortunately, their method that connects to the robot stops for 30 seconds when the IP parameter is faulty and this essentially freezes the UI.
I decided to use async/await to fix this issue, based on this I figured it is an I/O-Bound problem, but since the method I use to connect to the robot is sync, I couldn't await it. In the examples I saw they usually used async libraries at the first place and I couldn't find how to solve this problem, when a sync method is provided by 3rd party is freezing my UI.
The first code snippet didn't work, my UI stopped for 30 seconds when I tried to connect.
public async Task<bool> ConnectToRobot(string ip = "")
{
if (FanucController.IsConnected)
return true;
var result = await ConnectToFanuc(ip);
return result;
}
private Task<bool> ConnectToFanuc(string ip)
{
try
{
((IRobot)FanucController).Connect(ip);
// Other code for connection
return Task.FromResult(true);
}
catch
{
return Task.FromResult(false);
}
}
Eventually I got around it by using the CPU-Bound example (second code snippet), however, this is not really a CPU bound problem, hence I'm not sure if this would cause problems in the future.
public async Task<bool> ConnectToRobot(string ip = "")
{
if (FanucController.IsConnected)
return true;
var result = await Task.Run(() => ConnectToFanuc(ip));
return result;
}
private bool ConnectToFanuc(string ip)
{
try
{
((IRobot)FanucController).Connect(ip);
// Other code for connection
return true;
}
catch
{
return false;
}
}
Is there a better way to solve this problem? Should I use something other than the async/await keywords?
I think you have completely misunderstood what .net async is doing.
Task<T> is an implementation of the Promise monad.
This can be in a variety of states (very simply).
Not Complete
Complete with Result
Complete with Error
This is how the async/await engine does its magic. Methods can "complete" without a result.
Task.FromResult creates a Promise in the 2nd state. That means the the async/await engine has no chance to go off and do something else whilst waiting for the result.
One problem with the .net async await framework is the "Turtles/Async all the way down" problem. For async await to work properly, you need everything going down to be using the new fangled async/Task implementation (which is a pain since in general, that means reimplementing the entire library again).
A quick work-around for this is to use Task.Run. It is an acceptable workaround, for 3rd party libraries which do not support async/await.
Using Task.Run to make asynchronous wrappers around synchronous methods is generally considered a bad practice unless you want to offload the current thread to prevent it from freezing while waiting for the synchronous method complete.
So since ConnectToFanuc is obviously not asynchronous in this case, it is a viable workaround to use await Task.Run to call it.
Please refer to this blog for more information about this.

Akavache's GetObject<T> hangs when awaited. Any idea what is wrong here?

I have a Xamarin.Forms application, with this code in my App class (yes, this is just a sample to demonstrate the issue):
public App()
{
BlobCache.ApplicationName = "MyApp";
BlobCache.EnsureInitialized();
// The root page of your application
MainPage = GetMainPage();
}
public object BlockingGetExternalUser()
{
return GetExternalUser().Result;
}
private async Task<object> GetExternalUser()
{
try
{
return await BlobCache.LocalMachine.GetObject<object>("user");
}
catch (KeyNotFoundException)
{
return null;
}
}
The Key "user" does not exist, so I would expect to get a KeyNotFoundException. However I never see this exception being thrown. Instead it just "hangs" and never returns from the await GetObject call.
I am running this on my phone with Android 5.0.
Any ideas how to fix this? Am I doing something fundamentally wrong?
Update: On a side note: Instead of immediately trying GetObject, one could try to check if the key actually exists in the cache and only then retrieve it from the cache. However, if I am not mistaken, there is no other way to do a check other than calling GetObject and catching the exception like in the sample above. For a scenario where one would just want to know if an item exists, that doesn't seem to be ideal. Maybe an "Exists()" method would be a nice to have in Akavache? Or maybe I am missing something?
Update2: Changing the example to not use an async method in the constructor. Just to prove a point that that is not the issue.
Update3: Removing the call from the constructor. When I call BlockingGetExternalUser from anywhere in my code, the await will still hang.
You're most certainly having a dead-lock. Quoting Synchronously waiting for an async operation, and why does Wait() freeze the program here:
The await inside your asynchronous method is trying to come back to the UI thread.
Since the UI thread is busy waiting for the entire task to complete, you have a > deadlock.
Note that your call to .Result implies a Task.Wait() somewhere.
There are two solutions: Either completely avoid the async methods, or wrap your code into a Task.Run like this:
public object BlockingGetExternalUser()
{
return Task.Run<object>(() => GetExternalUser().Result);
}
(I hope it's compiling I didn't verify in VS :)
By experience I tend to avoid async methods in combination with SQLite these days. Reason is that most SQLite wrapper libraries use the Task.Run anti-pattern to provide async wrappers around their methods while SQLite doesn't have any intrinsic notations of being asynchronous. Note though that it's perfectly fine for you to wrap things into Task.Run to make them asynchronous and that it's only an anti-pattern for library designers, suggesting to their users that methods are asynchronous when they're actually not. You can read more about this here: Task.Run as an anti-pattern?
Using async methods in a constructors (var externalUser = GetExternalUser().Result;) is considered as a bad code. You shouldn't use async methods in a class constructors. Read this: Can constructors be async?
You could try to change it to avoid deadlocks:
Func<Task> task = async () => { await GetExternalUser().ConfigureAwait(false); };
task().Wait();
... but I won't recommend it.

Fire and forget async method in ASP.NET MVC

The general answers such as here and here to fire-and-forget questions is not to use async/await, but to use Task.Run or TaskFactory.StartNew passing in the synchronous method instead. However, sometimes the method that I want to fire-and-forget is async and there is no equivalent sync method.
Update Note/Warning: As Stephen Cleary pointed out below, it is dangerous to continue working on a request after you have sent the response. The reason is because the AppDomain may be shut down while that work is still in progress. See the link in his response for more information. Anyways, I just wanted to point that out upfront, so that I don't send anyone down the wrong path.
I think my case is valid because the actual work is done by a different system (different computer on a different server) so I only need to know that the message has left for that system. If there is an exception there is nothing that the server or user can do about it and it does not affect the user, all I need to do is refer to the exception log and clean up manually (or implement some automated mechanism). If the AppDomain is shut down I will have a residual file in a remote system, but I will pick that up as part of my usual maintenance cycle and since its existence is no longer known by my web server (database) and its name is uniquely timestamped, it will not cause any issues while it still lingers.
It would be ideal if I had access to a persistence mechanism as Stephen Cleary pointed out, but unfortunately I don't at this time.
I considered just pretending that the DeleteFoo request has completed fine on the client side (javascript) while keeping the request open, but I need information in the response to continue, so it would hold things up.
So, the original question...
for example:
//External library
public async Task DeleteFooAsync();
In my asp.net mvc code I want to call DeleteFooAsync in a fire-and-forget fashion - I don't want to hold up the response waiting for DeleteFooAsync to complete. If DeleteFooAsync fails (or throws an exception) for some reason, there is nothing that the user or the program can do about it so I just want to log an error.
Now, I know that any exceptions will result in unobserved exceptions, so the simplest case I can think of is:
//In my code
Task deleteTask = DeleteFooAsync()
//In my App_Start
TaskScheduler.UnobservedTaskException += ( sender, e ) =>
{
m_log.Debug( "Unobserved exception! This exception would have been unobserved: {0}", e.Exception );
e.SetObserved();
};
Are there any risks in doing this?
The other option that I can think of is to make my own wrapper such as:
private void async DeleteFooWrapperAsync()
{
try
{
await DeleteFooAsync();
}
catch(Exception exception )
{
m_log.Error("DeleteFooAsync failed: " + exception.ToString());
}
}
and then call that with TaskFactory.StartNew (probably wrapping in an async action). However this seems like a lot of wrapper code each time I want to call an async method in a fire-and-forget fashion.
My question is, what it the correct way to call an async method in a fire-and-forget fashion?
UPDATE:
Well, I found that the following in my controller (not that the controller action needs to be async because there are other async calls that are awaited):
[AcceptVerbs( HttpVerbs.Post )]
public async Task<JsonResult> DeleteItemAsync()
{
Task deleteTask = DeleteFooAsync();
...
}
caused an exception of the form:
Unhandled Exception: System.NullReferenceException: Object reference
not set to an instance of an object. at System.Web.ThreadContext.AssociateWithCurrentThread(BooleansetImpersonationContext)
This is discussed here and seems to be to do with the SynchronizationContext and 'the returned Task was transitioned to a terminal state before all async work completed'.
So, the only method that worked was:
Task foo = Task.Run( () => DeleteFooAsync() );
My understanding of why this works is because StartNew gets a new thread for DeleteFooAsync to work on.
Sadly, Scott's suggestion below does not work for handling exceptions in this case, because foo is not a DeleteFooAsync task anymore, but rather the task from Task.Run, so does not handle the exceptions from DeleteFooAsync. My UnobservedTaskException does eventually get called, so at least that still works.
So, I guess the question still stands, how do you do fire-and-forget an async method in asp.net mvc?
First off, let me point out that "fire and forget" is almost always a mistake in ASP.NET applications. "Fire and forget" is only an acceptable approach if you don't care whether DeleteFooAsync actually completes.
If you're willing to accept that limitation, I have some code on my blog that will register tasks with the ASP.NET runtime, and it accepts both synchronous and asynchronous work.
You can write a one-time wrapper method for logging exceptions as such:
private async Task LogExceptionsAsync(Func<Task> code)
{
try
{
await code();
}
catch(Exception exception)
{
m_log.Error("Call failed: " + exception.ToString());
}
}
And then use the BackgroundTaskManager from my blog as such:
BackgroundTaskManager.Run(() => LogExceptionsAsync(() => DeleteFooAsync()));
Alternatively, you can keep TaskScheduler.UnobservedTaskException and just call it like this:
BackgroundTaskManager.Run(() => DeleteFooAsync());
As of .NET 4.5.2, you can do the following
HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => await LongMethodAsync());
But it only works within ASP.NET domain
The HostingEnvironment.QueueBackgroundWorkItem method lets you
schedule small background work items. ASP.NET tracks these items and
prevents IIS from abruptly terminating the worker process until all
background work items have completed. This method can't be called
outside an ASP.NET managed app domain.
More here: https://msdn.microsoft.com/en-us/library/ms171868(v=vs.110).aspx#v452
The best way to handle it is use the ContinueWith method and pass in the OnlyOnFaulted option.
private void button1_Click(object sender, EventArgs e)
{
var deleteFooTask = DeleteFooAsync();
deleteFooTask.ContinueWith(ErrorHandeler, TaskContinuationOptions.OnlyOnFaulted);
}
private void ErrorHandeler(Task obj)
{
MessageBox.Show(String.Format("Exception happened in the background of DeleteFooAsync.\n{0}", obj.Exception));
}
public async Task DeleteFooAsync()
{
await Task.Delay(5000);
throw new Exception("Oops");
}
Where I put my message box you would put your logger.

Await alternative in .NET 4.0?

What would be the best alternative for the await keyword in .NET 4.0 ? I have a method which needs to return a value after an asynchronous operation. I noticed the wait() method blocks the thread completely thus rendering the asynchronous operation useless. What are my options to run the async operation while still freeing the UI thread ?
I think your basic options are
Using Task and .ContinueWith()
Using the Async CTP and async / await
Using Reactive Extensions
The easiest way is probably to install the Async CTP. As far as I know the license allows comercial usage. It patches the compiler and comes with a 150kb dll that you can include into your project.
You can use Task and .ContinueWith(). But that means, that you have to take some effort with exeption handling and flow control.
Tasks are a functional construct. That's why ContinueWith() does not mix well with imperative constructs like for loops or try-catch blocks. Therefore async and await got introduced, so that the compiler can help us out.
If you can't have that support of the compiler (i.e. you use .Net 4.0), your best bet is to use the TAP together with a functional framework. Reactive Extensions is a very good framework to treat asynchronous methods.
Just google for "reactive extensions tasks" to get started.
You could implement a behaviour like await with the yield coroutines, i'm using this in non-4.5 code. You need a YieldInstruction class which is retrieved from the method which should run async:
public abstract class YieldInstruction
{
public abstract Boolean IsFinished();
}
Then you need some implementations of the YieldInstruction ( a.e. TaskCoroutine which handles a task ) and use it this way ( Pseudo code ):
public IEnumerator<YieldInstruction> DoAsync()
{
HttpClient client = ....;
String result;
yield return new TaskCoroutine(() => { result = client.DownloadAsync(); });
// Process result here
}
Now you need a scheduler which handles the execution of the instructions.
for (Coroutine item in coroutines)
{
if (item.CurrentInstruction.IsFinished())
{
// Move to the next instruction and check if coroutine has been finished
if (item.MoveNext()) Remove(item);
}
}
When developing WPF or WinForms applications you are also able to avoid any Invoke calls if you are updating the coroutines at the right time. You also might be able to extend the idea to make your life even easier. Sample:
public IEnumerator<YieldInstruction> DoAsync()
{
HttpClient client = ....;
client.DownloadAsync(..);
String result;
while (client.IsDownloading)
{
// Update the progress bar
progressBar.Value = client.Progress;
// Wait one update
yield return YieldInstruction.WaitOneUpdate;
}
// Process result here
}

Categories