Handling exception in task - c#

I'm new to TPL.
I need to handle exception when the SendEmailAlert() method throws any error.Is the following code correct please?
public Task MyMethod()
{
DoSomething();
try
{
string emailBody = "TestBody";
string emailSubject = "TestSubject";
Task.Run(()=> SendEmailAlert(arrEmailInfo));
}
catch (AggregateException ex)
{
ex.Handle((e) =>
{
log.Error("Error occured while sending email...", e);
return true;
}
);
}
}
private void SendEmailAlert(string[] arrEmailInfo)
{
MyClassX.SendAlert(arrEmailnfo[0], arrEmailnfo[1]);
}
I forced an error from within SendEmailAlert() method.But the exception is not getting caught. Could someone advise?
Thanks.

Your Task.Run runs in a different context (you would need a try/catch inside it; or check if the task is done). You could change to use async/await.
Example:
public async void MyMethod()
{
try
{
await ExceptionMethod();
}
catch (Exception ex)
{
// got it
}
}
public async Task ExceptionMethod()
{
throw new Exception();
}

Related

Catch exception of a async method

Hello I want to catch a Exception of a async method but it did not work look a this example :
public void TryToCatchException()
{
try
{
_ =LongRunningMethod();
}
catch (MyException)
{
Console.WriteLine("catched");
}
}
public static async Task LongRunningMethod()
{
await Task.Run(() =>
{
try
{
Task.Delay(1000); //simulation of work
throw new ArgumentException(); // this is a example
}
catch (ArgumentException)
{
throw new MyException;
}
});
}
if I launch the debugger will say that the exception "MyException" is NOT catched... can someone help me ?
When you discard tasks, those exceptions are not observed:
_ =LongRunningMethod();
If you want to catch exceptions from LongRunningMethod, then you need to await the task returned from that method:
await LongRunningMethod();

Exception not being caught by first catch, and instead get handled by a top level catch

I have a class called SearchProbe for I'm writing unit tests. One unit test is for testing the ability of my class's main processing method (called RunSearchProbe) to be able to respond to CancellationTokens correctly. My class's main processing method executes async submethods which all throw an OperationCanceledException when a CancellationToken is cancelled. Then in my main method RunSearchProbe, I'm trying to catch this exception and respond to it.
Problem: The problem is that for some reason, OperationCanceledException is NOT being caught in the main method RunSearchProbe, and it comes all the way upto my unit test's call stack for handling, and I don't know why ?!
Here's my main class:
public class SearchProbe
{
protected async Task RunSearchProbe(CancellationToken cancellationToken) {
try
{
try
{
using (cancellationToken.Register(() => {
//some code here
}))
{
Task<bool> initTask = Initialize(cancellationToken);
await initTask;
//some code here
}
}
catch (Exception exception) when (exception.GetType().Equals(typeof(OperationCanceledException))
|| exception.InnerException.GetType().Equals(typeof(OperationCanceledException)))
{
//some code here // -------->>> (Point 1) This is where the OperationCanceledException SHOULD get caught
}
finally
{
//some code here
}
}
catch (Exception e)
{
//some code here // -------->>> (Point 2) ... Or AT LEAST get caught here
}
}
private async Task<bool> Initialize(CancellationToken cancellationToken) {
try
{
using (cancellationToken.Register(() => {
throw new OperationCanceledException();
}))
{
//some code here
return true;
}
}
catch (Exception exception)
{
//some code here
}
}
}
This is a mock inherited class:
class MockSearchProbe : SearchProbe
{
static MockSearchProbe()
{
//some code here
}
public async Task RunProbeManually()
{
try {
CancellationTokenSource cts = new CancellationTokenSource();
Task probeTask = RunSearchProbe(cts.Token);
cts.Cancel();
await probeTask;
}
catch (Exception exception) when (exception.GetType().Equals(typeof(OperationCanceledException))
|| exception.InnerException.GetType().Equals(typeof(OperationCanceledException)))
{
//do something (Point 3) ... But it actually gets caught here for some reason
}
}
}
This is the test class:
[TestClass]
public class SearchProbeTests
{
[TestMethod]
public async Task TestProbe_Cancellation()
{
MockSearchProbe probe = new MockSearchProbe();
Task result = probe.RunProbeManually();
await result;
}
}
Please see steps 1, 2 and 3 commented above to see what I mean ... Why is the catch block inside my main class's RunSearchProbe method NOT catching the OperationCanceledException ??
The documentation for CancellationToken.Regsiter states that the method:
Registers a delegate that will be called when this CancellationToken is canceled.
Based on that description, I would expect that the registration callback defined in the Initialize method should execute when cts.Cancel() is called in RunProbeManually. The exception is not instantiated or thrown until that point, which is in the scope of the try/catch block labeled "Point 3."
Here's a simplified illustration:
using System;
class MainClass {
public static void Main (string[] args) {
Action throwException = null;
try {
Console.WriteLine("Defining delegate");
throwException = () => {
Console.WriteLine("Throwing exception");
throw new Exception();
};
} catch (Exception) {
Console.WriteLine("Exception caught at point 1");
}
try {
Console.WriteLine("Invoking delegate");
throwException.Invoke();
} catch (Exception) {
Console.WriteLine ("Exception caught at point 2");
}
}
}
Output:
Defining delegate
Invoking delegate
Throwing exception
Exception caught at point 2

Rethrowing inner exception of an AggregateException

Let's say I have an Interface:
interface A {
string Do();
}
and then I implement this interface in a class. The implementation requires some async operations. Something like the following:
class B : A {
public string Do() {
return Task1().Result;
}
private async Task<string> Task1() {
var str = await Task2();
return str + "task1";
}
private async Task<string> Task2() {
using (WebClient client = new WebClient())
{
return System.Text.Encoding.UTF8.GetString(await client.DownloadDataTaskAsync(new Uri("http://test.com")));
}
}
}
What is the proper way to return, to the external calling code, the first exception that occurs in the async operations chain? Is the following a good approach?
public string Do() {
try {
return Task1().Result;
} catch (AggregateException ex) {
Exception inner = ex;
while(inner.InnerException != null) {
inner = inner.InnerException;
}
throw inner;
}
}
From your code, through the while, I think you want to throw the first exception in AggregateException
To do that, you can use Flatten
Flattens an AggregateException instances into a single, new instance.
It helps to put the exceptions in "the same hierarchy", you can then simply call FirstOrDefault to get the first exception.
Supposed this code:
Task.Factory.StartNew(
async () =>
{
await Task.Factory.StartNew(
() => { throw new Exception("inner"); },
TaskCreationOptions.AttachedToParent);
throw new Exception("outer");
}).Wait();
}
The stucture of exceptions likes
AggregateException
Exception: outer
AggregateException
Exception: inner
With Flatten, I can get inner
catch(AggregateException ex)
{
Console.WriteLine(ex.Flatten().InnerExceptions.FirstOrDefault().Message);
}
but without Flatten, I get AggregateException, which isn't correct
catch(AggregateException ex)
{
Console.WriteLine(ex.Flatten().InnerExceptions.FirstOrDefault().Message);
}
With your case, this line can help you get the first exception
ex.Flatten().InnerExceptions.FirstOrDefault().Message
You have also the method Handle, which help you handle the exception inside AggregateException
catch (AggregateException ex)
{
ex.Handle(x =>
{
if (x is UnauthorizedAccessException)
{
//the exception you interested
throw x;
}
// Other exceptions will not be handled here.
//some action i.e log
return false;
});
}

Xamarin: Exceptions raised from tasks are not propagated

I have the following code in Xamarin (tested in ios):
private static async Task<string> TaskWithException()
{
return await Task.Factory.StartNew (() => {
throw new Exception ("Booo!");
return "";
});
}
public static async Task<string> RunTask()
{
try
{
return await TaskWithException ();
}
catch(Exception ex)
{
Console.WriteLine (ex.ToString());
throw;
}
}
Invoking this as await RunTask(), does throw the exception from the TaskWithException method, but the catch method in RunTask is never hit. Why is that? I would expect the catch to work just like in Microsoft's implementation of async/await. Am I missing something?
You cant await a method inside of a constructor, so thats why you can't catch the Exception.
To catch the Exception you must await the operation.
I have here two ways of calling an async method from the constructor:
1. ContinueWith solution
RunTask().ContinueWith((result) =>
{
if (result.IsFaulted)
{
var exp = result.Exception;
}
});
2. Xamarin Forms
Device.BeginInvokeOnMainThread(async () =>
{
try
{
await RunTask();
}
catch (Exception ex)
{
Console.WriteLine (ex.ToString());
}
});
3. iOS
InvokeOnMainThread(async () =>
{
try
{
await RunTask();
}
catch (Exception ex)
{
Console.WriteLine (ex.ToString());
}
});

Exception not thrown in an async Task configuration

I have the following method
public async Task<bool> Connect()
{
lock (_connectingLock)
{
if (_connecting)
throw new IOException("Already connecting");
_connecting = true;
}
try {
await tcpClient.ConnectAsync(...);
}
catch (SocketException e)
{
return false;
}
finally
{
lock (_connectingLock)
{
_connecting = false;
}
}
}
Now, I would expect consecutive calls to Connect() to throw an IOException, but it doesn't happen!
What could be the cause?
Calls to Connect() can't throw exceptions directly. Async methods do not throw exceptions. Instead, they will return tasks which, when awaited, will throw IOException. (i.e. the tasks are faulted.)
If that's not what you want, you should separate the calls:
public Task<bool> Connect()
{
// Eager validation of state...
lock (_connectingLock)
{
if (_connecting)
throw new IOException("Already connecting");
_connecting = true;
}
return ConnectImpl();
}
private async Task<bool> ConnectImpl()
{
try {
await tcpClient.ConnectAsync(...);
}
catch (SocketException e)
{
return false;
}
finally
{
lock (_connectingLock)
{
_connecting = false;
}
}
}
It's not clear whether that's appropriate in this case though. It's generally fine to throw things like ArgumentException eagerly, but if the error doesn't represent a bug in the calling code itself, I think returning a faulted task instead is fine.

Categories