Wait for async task on application exit from UI thread - c#

I'm writing an UI app. If some exception happens I need to do some work before application exit.
So I subscribed to AppDomain.CurrentDomain.UnhandledException event.
AppDomain.CurrentDomain.UnhandledException += HandleException;
HandleException method performs async saving to remote(because there are no sync api).
private void HandleException(object sender, UnhandledExceptionEventArgs args)
{
foreach (var user in UsersCollection.ToArray())
{
try
{
foreach (var session in user.Sessions.ToArray())
{
try
{
SaveSessionAsync(session).Wait();
}
catch (Exception e)
{
Logger.Error("Can't save session: " + session, e);
}
}
}
catch (Exception e)
{
Logger.Error("Can't save sessions of user " + user, e);
}
}
}
Before application exit I need to be sure that I saved all sessions(tried, at least). But if I put Wait() there I get a deadlock and application never stops.
As far as I know, await may help me in normal situation(when I'm in UI thread but not in app termination state), but await does not awaits on application exit. So my saving tasks may be aborted. But I need them to finish.
Is there a way of waiting for guaranteed finish of SaveSessionAsync task without creating a deadlock?
BTW: SaveSessionAsync has Parse.com API inside

You only used part of the syntax you need to run it in a non-async method. Utilizing Task.Run() will run it in an asynchronous fashion without having to use await.
Try this:
Task.Run(() => SaveSessionAsync(session)).Wait();

Related

C# WPF - ApplicationExit calling an API

I have to call an API when my WPF Applications is being closed.
I'm using Application_Exit event because I have to do this even closing all the windows, being shut down from Task Manager or Alt + F4.
I've tried several ways, but all the options has some issues (some of them are these):
OPTION A: Async event + await
private async void Application_Exit(object sender, ExitEventArgs e)
{
if (MonitorInstance.Instance.User != null)
{
Log.Information($"Disconnect starting");
var result = await _apiClient.Disconnect();
Log.Information($"Disconnect result: {result}");
}
}
This option just calls the HTTP CONNECT (which sometimes succeed and others is being cancelled) but not my PATCH request.
OPTION B: Blocking Thread with Result of Task.
private void Application_Exit(object sender, ExitEventArgs e)
{
if (MonitorInstance.Instance.User != null)
{
Log.Information($"Disconnect starting");
var result = _apiClient.Disconnect().Result;
Log.Information($"Disconnect result: {result}");
}
}
This effectively calls the API but the process continues running. Visual Studio continues showing that the App is running and this is not desired.
I think it's worth to mention that I'm calling the API (which uses SSL) using HttpClient which is being created in the Disconnect method and I'm using .NET Core 3.1.
My questions:
Is Application_Exit the proper event to do this?
How to program the Application_Exit event to fulfill all the scenarios?
Should I change the implementation for my call to do it directly without the HttpClient?
This a classic case of deadlock. Your code is running under a synchronization context, your await calls inside of _apiClient.Disconnect() try to resume on the UI thread, but the UI thread is blocked waiting synchronously on the task because of .Result.
There are multiple ways to get around that, but for your precise case I don't think it's useful to get fancy. Just use Task.Run to run your call in a safer context:
private void Application_Exit(object sender, ExitEventArgs e)
{
if (MonitorInstance.Instance.User != null)
{
Log.Information($"Disconnect starting");
var result = Task.Run(apiClient.Disconnect).Result;
Log.Information($"Disconnect result: {result}");
}
}

C# - return boolean from Async method

I have Async method which is called inside button_click. Async method runs 3 different void's and each void has It's own error handling. If any error inside those 3 methods occure I want to show that particular error message and stop code inside button_click - which also runs more non-async method and has It's error handling. What I did was this (example):
private void button1_Click(object sender, EventArgs e)
{
try
{
//calling non-async method, if It fails It should show error
//inside this event
Method1();
if (TestAsync().IsCanceled)
{
return;
}
MessageBox.Show("Test");
}
catch (Exception)
{
MessageBox.Show("Async method failed and this message should not be diplayed!");
throw;
}
}
public async Task<bool> TestAsync()
{
bool completed = await Task.Run(() => MethodToComplete());
return completed;
}
private bool MethodToComplete()
{
try
{
//renaming file, but intentionally fail for test purpose
Directory.Move("fail_this_method", "fail");
return true;
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
return true;
throw;
}
}
The result of this example is - It does display error message from void which is called asynchronously and doesn't show error message from button_click. But It also displays MessageBox.Show("Test"); which shouldn't, code in button_click should stop immidiately if Async fails.
I hope I was clear enough, any help kindly appreaciated !
Before async-await there were other task handling methods, like Task.ContinueWith, Task.IsCanceled etc.
If you plan to use async-await, don't mix them with these older functions.
When you decide to use async-await, stick to the following rules:
only declare a function async if it awaits a call to another async function
every async function should return Task<TResult> instead of TResult and Task instead of void
There is one exception: an async event handler returns void
Furthermore:
If you call an async function, but you do not need the result immediately, consider not to await yet, but do the other things. Start awaiting when you need the results of the async function
After the await the thread that continues may be a different thread. But it has the same context. This has the effect that you can regard this as if it is the original thread. No need for InvokeRequired, locks and mutexes
If you don't need the same context, consider ConfigureAwait(false) after the await. This will speed up the process, with the disadvantage that the continuing thread does not have the user interface context. Therefore you can't access windows Form controls.
Keeping this in mind, you code could be as follows:
private async void button1_Click(object sender, EventArgs e)
{
// this function must be async because if awaits
// it is an event hander, hence it returns void instead of Task
try
{
Method1();
// call TestAsync, if you do not need the result right now,
// do not await yet
var myTask = TestAsync();
// as soon as TestAsync has to await, it continues here:
// results from TestAsync are not available yet
DoSomeOtherProcessing();
// now you need the result from testAsync; await the Task
bool result = await myTask;
ProcessResult(result);
}
catch (Exception)
{
...
}
}
A Task that is cancelled, should throw TaskCanceledException. You should not check MyTask.IsCanceled, but catch this exception.
Articles that helped me understanding async-await
This interview with Eric Lippert Search somewhere in the middle for async-await. Eric compares async-await with a cook making dinner. Once he put on the kettle, he does not idly wait for the water to boil, but looks around to see if he can do other things instead, like chopping onions
async-await by the ever so helpful Stephen Cleary

MSMQ - ReceiveCompleted - Process Messages async

I am using the BeginnReceive method and ReceiveCompleted eventhandler to listen and process messages from a MSMQ.
I have put the BeginReceive method at the beginning of the ReceiveCompleted eventhandler.
It looks like it's working fine in my console application.
Right now, the messages are processed asynchronously.
Question:
Is this safe regarding thread-safety?
All examples I saw put the BeginReceive call to the end of the completed eventhandler. So I ask myself are there any issues when putting it at the very beginning of the completed handler?
private void InitializeQueue()
{
try
{
_mq = MessageQueue.GetPrivateQueuesByMachine(_queueServerName).Where(qu => qu.Path == _queueAddress).FirstOrDefault();
_mq.Formatter = new BinaryMessageFormatter();
_mq.ReceiveCompleted += MessageReceiveCompleted;
}
catch (Exception ex)
{
Trace.WriteLine("Failed to initialize Queue!" + Environment.NewLine + " Error:" + Environment.NewLine + ex.Message);
throw;
}
}
async void MessageReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
_mq.BeginReceive();
try
{
await ProcessMessageAsync(e.Message);
}
catch (Exception ex)
{
Trace.WriteLine("Error occured during report fetching:" + Environment.NewLine + ex.Message);
throw;
}
}
Yes your approach with async/await will handle the threads safely.c# asynchronous approach with these keywords will take care.
Being more specific about my answer the event handler method messagereceived (the method name should end with async)calls and awaits on the async method, if there is any blocking work inside this method the thread it's suspends there and executes further until other work finishes and returns, like in this case the processmessage async might be blocking and there can be further execution of call but I don't see you leverage it since there is nothing you are doing after calling processmessageasync,so the thread will be executing this if you ask if it's thread safe yes but asynchronous approach is not fully leveraged

Rethrowing exceptions in tasks c# without wait

I have a GUI application, in which I want to run something in a task, so it will not hold the UI. I want un unhandled exception in the task to be propogated to the application level exception handler.
However:
If I just throw an exception in the task it will not reach app level
exceptions unless I use wait/await
Async/Await - I call the method from a UI constructor, so I can't use async/await there, since I need to continue with the consturction. I just want to run the task and forget.
I was thinking about using dispatcher.invoke, what do you think?
public MainWindow()
{
InitializeComponent();
MyMethodAsync();
InitializeA();
IntiializeB();
}
private void MyMethodAsync()
{
Task t = Task.Run(() =>
{
//Do some stuff
throw new Exception("Throwing some unexpected exception");
}).ContinueWith(MyContinueWith);
}
private void MyContinueWith(Task task)
{
if (task.IsFaulted && task.Exception != null)
{
dispatcher.BeginInvoke(new Action(() =>
{
throw task.Exception;
}), null);
}
}
Two ways I can think of. First, is register to TaskScheduler.UnobservedTaskException event and log whatever you need there:
private void MyMethodAsync()
{
// Note you should probably register only once, so this may not fit here.
TaskScheduler.UnobservedTaskException += (s, e) => GlobalLogger.Log(e);
Task t = Task.Run(() =>
{
// Do some staff
}).ContinueWith(MyContinueWith);
}
The better option which for some reason you don't want to use, is to actually await the operation and wrap it in a try-catch:
private async Task MyMethodAsync()
{
try
{
await Task.Run(() =>
{
// Do some staff
});
InvokeContinuation();
}
catch (Exception e)
{
// Log.
}
}
Do realize that by calling Task.Run you are generally spawning a new thread which is not likely what you want most of the time. Creating new threads makes sense in some instances where you are doing CPU bound work and in those cases you'll want to consider leveraging other Parallel computation libraries to get the most out of it. Instead if your work is I/O bound you should be able to use asynchronous calls all the way down.
In order to wait for the result of a async method call or an exception bubbled up to the call point you can always tack on a call to ContinueWith to the a task that is returned by the async method. If you are handling both the result and any possible exceptions then async/await semantics work nice. Note however that the code that executes in these continuations may not execute in the same thread as the original thread by default.

External Function Call Blocks UI thread

I am working on an application that talks to a motion controller over ethernet.
To connect to the controller I use a library provided by the supplier, to connect you create an instance of the controller than then tell it to connect, this has the chance to block for a few seconds (with no controllable timeout) if there is no controller present. This cause freeze ups in the UI.
To avoid this I thought I would be able to use Tasks to run the connection in a different thread.
ConnectionTask = Task.Factory.StartNew(() =>
{
try
{
RMCLink rmc = RMCLink.CreateEthernetLink(DeviceType.RMC70, "192.168.0.55");
RMC.Connect();
}
catch
{
this.logger.Log("Failed to connect");
}
}, TaskCreationOptions.LongRunning);
This has no effect whatsoever and the UI still locks up.
I think I am using them properly as if I replace it with the below code the UI is fine even though the separate thread takes a few seconds before the message comes out.
ConnectionTask = Task.Factory.StartNew(() =>
{
int x = 1;
while (x != 0) x++;
this.logger.Log("Failed to connect");
}, TaskCreationOptions.LongRunning);
Is there any way I can identify what is going on and prevent calls that I do not know anything about their inner workings from locking the UI thread.
Use async/await, something along the lines of:
public async void MyButton_Click(object sender, EventArgs e)
{
await CreateEthernetLink();
this.logger.Log("Connected!");
}
private async Task CreateEthernetLink()
{
var task = Task.Run(() => {
try
{
RMCLink rmc = RMCLink.CreateEthernetLink(DeviceType.RMC70, "192.168.0.55");
rmc.Connect();
}
catch
{
this.logger.Log("Failed to connect");
}});
await task;
}
The await will capture the current thread (or SynchronizationContext - in this case the UI thread which is being blocked) and restore it after the async work has been completed.
So the threading is all handled for you behind the scenes and you should notice no difference in your application other than the fact that your application no longer freezes when performing connections.
EDIT: I also noticed in your code your initializing rmc but calling connect on RMC. I don't think this is correct.

Categories