Consider the following code:
void TopLevelCaller() {
RecursiveAwaiter();
}
async Task RecursiveAwaiter() {
var result = await ReceiveDataAsync();
FireEvent(result);
RecursiveAwaiter();
}
Suppose ReceiveDataAsync fails with an exception.
Is it possible modify the code to catch this exception in the TopLevelCaller() such that all error handling can be done in the class where TopLevelCaller() exists?
It would be better to let the implementer handle the error like so:
void TopLevelCaller() {
try {
RecursiveAwaiter();
} catch (Exception e)
{
// Something went wrong. Handle appropriately.
}
}
than to have something like:
async Task RecursiveAwaiter() {
try {
var result = await ReceiveDataAsync();
FireEvent(result);
RecursiveAwaiter();
} catch (Exception e) {
FireExceptionEvent(e);
}
}
async void TopLevelCaller()
async void is almost always bad idea. It is designed for WPF control events. This is fire and forget function so i.e. you won't be able to catch exceptions which TopLevelCaller throws. It should be working:
async Task TopLevelCaller() {
try {
await RecursiveAwaiter();
} catch (Exception e)
{
// Something went wrong. Handle appropriately.
}
}
Related
I Have a class, that should not show any dialogs to final user. In case, that user passed wrong filepath, i tried to throw and exception and handle it in proper class.
However, despite 'throw' instruction, Visual Studio shows Exception Dialog and breaks application after it occurs (Debuging mode). In Release mode application just crashes after giving wrong filepath. What am i doing wrong?
GuyManager.cs:
private IStorageFile latestGuyFile;
public IStorageFile LatestGuyFile { get { return latestGuyFile; } }
public string Path { get; set; }
public async void ReadGuyAsync()
{
if (String.IsNullOrWhiteSpace(Path))
return;
try
{
latestGuyFile = await StorageFile.GetFileFromPathAsync(Path);
}
catch (Exception ex)
{
Debug.WriteLine("Error occured: " +ex.Message);
Debug.WriteLine(ex.StackTrace);
throw;
}
MainPage.xml.cs:
private async void loadGuy_Click(object sender, RoutedEventArgs e)
{
try
{
guyManager.ReadGuyAsync();
}
catch (Exception ex)
{
MessageDialog dialog = new MessageDialog("Error" + ex.Message);
await dialog.ShowAsync();
}
}
I see a problem in your Click event handler.
You define it as async, but you are not awaiting anything.
You should change the ReadGuyAsync method to return a Task instead of void, like this:
public async Task ReadGuyAsync()
and in the loadGuy_Click method, you should await it:
await guyManager.ReadGuyAync();
I'm having this code snippet:
class Program
{
public static async Task ProcessAsync(string s)
{
Console.WriteLine("call function");
if (s == null)
{
Console.WriteLine("throw");
throw new ArgumentNullException("s");
}
Console.WriteLine("print");
await Task.Run(() => Console.WriteLine(s));
Console.WriteLine("end");
}
public static void Main(string[] args)
{
try
{
ProcessAsync(null);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
}
It runs and prints:
call function
throw
Ok, and exception is thrown, but the main function's try/catch is not able to catch the exception, if I remove the try/catch, main doesn't report unhandled exception either. This is very weird, I googled and it says there's trap in [await] but doesn't explain how and why.
So my question, why here the exception is not caught, what's the pitfalls of using await?
Thanks a lot.
Within an async method, any exceptions are caught by the runtime and placed on the returned Task. If your code ignores the Task returned by an async method, then it will not observe those exceptions. Most tasks should be awaited at some point to observe their results (including exceptions).
The easiest solution is to make your Main asynchronous:
public static async Task Main(string[] args)
{
try
{
await ProcessAsync(null);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
For some reason I could not catch an exception thrown inside anonymous async delegate that subscribed to event.
It does not get caught inside TestTestAsync (I suppose because of invoke wait only fastest one) but why it is not caught in unhandled or unobserved or crash app?
ThrowUnobservedTaskExceptions = true also does not make any sense.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp5
{
class Program
{
static string lockStr = Guid.NewGuid().ToString();
public static void ConsoleWriteLine(string Message, ConsoleColor? color = null)
{
lock (lockStr)
{
var old = Console.ForegroundColor;
if (color != null)
Console.ForegroundColor = color.Value;
Console.WriteLine(Message);
if (color != null)
Console.ForegroundColor = old;
}
}
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
try
{
var cls = new TestClass();
cls.TestAsync += async (s) => await Cls_TestRealAsyncAsync(s);
cls.TestAsync += Cls_TestRealAsync;
Task.Run(async () => await cls.TestTestAsync()).Wait();
Thread.Sleep(5000);
}
catch (Exception ex)
{
ConsoleWriteLine($"{nameof(Main)}: {ex.Message}");
}
}
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
ConsoleWriteLine($"{nameof(TaskScheduler_UnobservedTaskException)}: {(e.Exception as Exception).Message}", ConsoleColor.Yellow);
}
private static Task Cls_TestRealAsync(object sender)
{
try
{
Thread.Sleep(100);
throw new NotImplementedException($"{nameof(Cls_TestRealAsync)}");
}
catch (Exception ex)
{
ConsoleWriteLine(ex.Message, ConsoleColor.Red);
throw;
}
}
private static async Task Cls_TestRealAsyncAsync(object sender)
{
try
{
await Task.Run(() => Thread.Sleep(1000));
throw new NotImplementedException($"{nameof(Cls_TestRealAsyncAsync)}");
}
catch (Exception ex)
{
ConsoleWriteLine(ex.Message, ConsoleColor.Red);
throw;
}
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ConsoleWriteLine($"{nameof(CurrentDomain_UnhandledException)}: {(e.ExceptionObject as Exception).Message}", ConsoleColor.Yellow);
}
}
public class TestClass
{
public delegate Task TestHandlerAsync(object sender);
public event TestHandlerAsync TestAsync;
private async Task OnTestAsync()
{
if (TestAsync != null)
await TestAsync.Invoke(this);
}
public async Task TestTestAsync()
{
try
{
await OnTestAsync();
}
catch (Exception ex)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {ex.Message}", ConsoleColor.Green);
}
}
}
}
PS: I made tests on 4.7.1
Asynchronous code is not necessarily concurrent code, but you should be careful anyway.
This:
private async Task OnTestAsync()
{
if (TestAsync != null)
await TestAsync.Invoke(this);
}
can get you in trouble because by the time TestAsync.Invoke is invoked, TestAsync can be null.
But the problem that you're trying to solve is that, not the that the fastest one is awaited but that the last one is awaited.
You should revise your API but, if you can't, try this:
public class TestClass
{
public delegate Task TestHandlerAsync(object sender);
public event TestHandlerAsync TestAsync;
private async Task OnTestAsync()
{
var testAsync = this.TestAsync;
if (testAsync == null)
{
return;
}
await Task.WhenAll(
from TestHandlerAsync d in testAsync.GetInvocationList()
select d.Invoke(this));
}
public async Task TestTestAsync()
{
try
{
await OnTestAsync();
}
catch (Exception ex)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {ex.Message}", ConsoleColor.Green);
}
}
}
if you only care to show the first exception.
Or:
public class TestClass
{
public delegate Task TestHandlerAsync(object sender);
public event TestHandlerAsync TestAsync;
private async Task<Exception[]> OnTestAsync()
{
var testAsync = this.TestAsync;
if (testAsync == null)
{
return new Exception[0];
}
return await Task.WhenAll(
from TestHandlerAsync d in testAsync.GetInvocationList()
select ExecuteAsync(d));
async Task<Exception> ExecuteAsync(TestHandlerAsync d)
{
try
{
await d(this);
return null;
}
catch (Exception ex)
{
return ex;
}
}
}
public async Task TestTestAsync()
{
try
{
var exceptions = await OnTestAsync();
foreach (var exception in exceptions)
{
if (exception != null)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {exception.Message}", ConsoleColor.Green);
}
}
}
catch (Exception ex)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {ex.Message}", ConsoleColor.Green);
}
}
}
if you care for all.
Found the answer. It not abandoned. It simply still not fired because of life of my test console was too short.
Unhandled exception will be thrown at GC.Collect()
https://blogs.msdn.microsoft.com/ptorr/2014/12/10/async-exceptions-in-c/
During GC, it notices that nobody ever checked the result (and
therefore never saw the exception) and so bubbles it up as an
unobserved exception.
So next code before main method end will solve issue and I see exception
GC.Collect();
Thread.Sleep(5000);
I need to call SendEmail() in my C# code below so that my program doesn't get blocked due to SendEmail() method taking a lot of time and or failing.
Here's my C# code:(I'm using .Net 4.5)
private void MyMethod()
{
DoSomething();
SendEmail();
}
Can I achieve the same using following please?Or is there any other better approach ?Is using async/await a better approach for achieving this?
public void MyMethod()
{
DoSomething();
try
{
string emailBody = "TestBody";
string emailSubject = "TestSubject";
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(SendEmailAlert), arrEmailInfo);
}
catch (Exception ex)
{
//Log error message
}
}
private void SendEmailAlert(object state)
{
string[] arrEmailnfo = state as string[];
MyClassX.SendAlert(arrEmailnfo[0], arrEmailnfo[1]);
}
And In case I need to make SendEmailAlert() method as fire and forget, I can use code like this Would that be correct? ---->
Task.Run(()=> SendEmailAlert(arrEmailInfo));
Thanks.
Async await can definitely help you. When you have CPU-bound work to do asynchronously, you can use Task.Run(). This method can be "awaited" so that the code will resume after the task is done.
Here's what I would do in your case:
public async Task MyMethod()
{
DoSomething();
try
{
string emailBody = "TestBody";
string emailSubject = "TestSubject";
await Task.Run(()=> SendEmailAlert(arrEmailInfo));
//Insert code to execute when SendEmailAlert is completed.
//Be aware that the SynchronizationContext is not the same once you have resumed. You might not be on the main thread here
}
catch (Exception ex)
{
//Log error message
}
}
private void SendEmailAlert(string[] arrEmailInfo)
{
MyClassX.SendAlert(arrEmailnfo[0], arrEmailnfo[1]);
}
I have the following code:
catch (ServiceException e) { se(e); return View("CreateEdit", vm); }
catch (Exception e) { ex(e); return View("CreateEdit", vm); }
return RedirectToAction("ShowSummary", new {
ds = vm.Meta.DataSourceID
});
protected void se(ServiceException e) {
ModelState.Merge(e.Errors);
}
protected void ex(Exception e) {
Trace.Write(e);
ModelState.AddModelError("", "Database access error: " + e.Message);
}
I would like to change this to something like:
catch (Exception e) { processException(e); return View("CreateEdit", vm); }
Is there a way that I can add code to a processException function that would be able
to check what kind of exception it is and then do action depending on if it is a ServiceException
or just a general exception? I just want to put all my exception handling in one place
and then call it.
You can use the is keyword like this
protected void processException(Exception e) {
if (e is XXXException)
{
this.doThis();
}
else if (e is YYYException)
{
this.doThat();
}
}
You can also use a switch statement and test the type of the e but IMO is is easier and better
You can use the typeOf(e) or e.GetType() and then do a switch or if statement on that.
Absolutely, we use this extensively in database exception handling.
public void processException(Exception ex)
{
if (ex is System.Threading.ThreadAbortException)
{
// Do something
}
else if (ex is AnotherException)
{
// Do something else
}
}