Catching errors with .NET Task Parallel Library - c#

Here are the two alternatives i tried for catching errors, they both seem to do the same thing.. but is one preferable over the other and why ?
Alt 1:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
Task t = Task.Run(() =>
{
_someObj.SomeMethod();
});
await t; //wait here, without blocking...
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
return; //<-- bypass below code on error...
}
//other code below... does not execute...
DoSomethingElse();
}
Alt 2:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool errOccurred = false;
Task t = Task.Run(() =>
{
try
{
_someObj.SomeMethod();
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
errOccurred = true;
}//end-Catch
});
await t; //wait here, without blocking...
if (errOccurred) return; //<-- bypass below code on error...
//other code below... does not execute...
DoSomethingElse();
}

Better option is to refactor part of the code into a separate method returning a bool indicating that whether to proceed or not.
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool success = await SomeMethodAsync();
if (!success)
{
return;
}
//other code below... does not execute...
DoSomethingElse();
}
private async Task<bool> SomeMethodAsync()
{
try
{
await Task.Run(() => _someObj.SomeMethod());
return true;
}
catch (Exception ex)
{
string errMsg = string.Format("{0} {1}some unhandled error occurred in SomeMethod",
ex.Message, Environment.NewLine);
Log(errMsg);
return false;
}
}

It's better to refactor the code than putting it all at the same place.It's better to catch the exception within your delegate if all you need to do is log it.
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
}
However If you have another method DoSomethingElse() which might be affected by the outcome of the Task.It's better to wrap try catch around await
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
DoSomethingElse();
}
catch(Exception ex)
{
}
}

As with anything it depends.
I'd say refactor the Task.Run() section into a separate async Task method, much like Sriram Sakthivel's answer, is in general a good thing. It avoids the use of a captured bool in the lambda as in version 2, and it lets you write code that expresses intent more concisely.
That said, I would carefully consider if the "catch all -> log -> ignore" pattern is what you want. In general: catch specific exceptions and handle them specifically. For all other exceptions, you might log them, but still rethrow them with "throw;" or "throw new MoreSpecificException(originalException);".
With that in mind I would suggest that if you do the catch all approach you should do the catch all as in version 1.
To keep readability high, make the code concise with clear intent, and be explicit about handling exceptions, I would write it something like this:
private async void BtnClick(object sender, RoutedEventArgs e)
{
try
{
if (await TryDoSomethingAsync())
{
DoSomeMoreStuff();
}
}
catch (Exception ex)
{
// I am sure it is fine that any and all exceptions can be logged and ignored.
Log(ex);
// And maybe even notify the user, since I mean, who monitors log files anyway?
// If something that shouldn't go wrong goes wrong, it's nice to know about it.
BlowUpInYourFace(ex);
}
}
private async Task<bool> TryDoSomethingAsync()
{
return await Task.Run<bool>(() =>
{
try
{
_myService.DoSomething();
}
catch (SomeKnownException ske)
{
// An expected exception which is fine to ignore and return unsuccessful.
Log(ske);
return false;
}
catch (SomeOtherKnownException soke)
{
// Expected exception that indicates something less trivial, but could be more precise.
throw new MyMorePreciseException(soke);
}
// Nothing went wrong, so ok.
return true;
});
}

Related

when to use await key word? do I need it in this case?

i have a onClick method on a buttom. when this button is pressed, i get a displayalert message.
getTokenQ has a value. my question why its going inside catch block?
private async void Button_Clicked(object sender, EventArgs e)
{
try
{
var getTokenQ = await SecureStorage.GetAsync("Save_Security_Question");
if ((String.IsNullOrWhiteSpace(getTokenQ) == false))
{
}
else
{
}
}
catch (Exception ex)
{
await DisplayAlert("Message", "Some thing went wrong. Please try different method", "ok");
}
}
no you don't need to do that, you can use .Result if you don't want to execute your code asynchronously , this code is perfectly fine :
private void Button_Clicked(object sender, EventArgs e)
{
try
{
var getTokenQ = SecureStorage.GetAsync("Save_Security_Question").Result;
if ((String.IsNullOrWhiteSpace(getTokenQ) == false))
{
}
else
{
}
}
catch (Exception ex)
{
DisplayAlert("Message", "Some thing went wrong. Please try different method", "ok");
}
}
Why in catch ! Because it's a message to display only if an exception is thrown.

Correct way to handle mulitple http Request async with error handling

The solution works, but is there a better way to handle multiple requests like this with the errorhandling.
The below code describes what i want to do, and absolutely works. But I'm sure there is a better way to go about the issue?
I've tried other options as well but it fails as some of the requests will return a 404.
public async Task<List<Bruker>> TryGetContactsByContactIds(List<AZContact> contacts)
{
var tasks = contacts.Select(c => TryGetContactAsync(c.Email)).Where(c => c.Result != null);
try
{
var tasksresult = await Task.WhenAll(tasks);
return tasksresult.ToList();
}
catch (Exception e)
{
_logger.Error("unable to fetch all", e);
}
return new List<Bruker>();
}
public async Task<Bruker> TryGetContactAsync(string userId)
{
try
{
var user = await _brukereClient.GetAsync(userId);
return user;
}
catch (SwaggerException e)
{
if (e.StatusCode == 404)
{
_logger.Info($"user with Id {userId} does not exist");
}
else
{
_logger.Error("Unable to fetch user", e);
}
}
return null;
}
You are probably dealing with a feature/limitation of await, that throws only one of the aggregated exceptions of the awaited task (the WhenAll task in this case). You must enumerate all the tasks to handle each individual exception.
try
{
var tasksresult = await Task.WhenAll(tasks);
return tasksresult.ToList();
}
catch (Exception e)
{
foreach (var task in tasks)
{
if (task.IsFaulted)
{
var taskException = task.Exception.InnerException;
// ^^ Assuming that each task cannot have more than one exception inside its AggregateException.
if (taskException is SwaggerException swaggerException)
{
if (swaggerException.StatusCode == 404)
{
_logger.Info($"user with Id {userId} does not exist");
}
else
{
_logger.Error("Unable to fetch user", swaggerException);
}
}
else
{
_logger.Error("An unexpected task error occurred", taskException);
}
}
}
if (!tasks.Any(t => t.IsFaulted))
{
_logger.Error("A non task-related error occurred", e);
}
}

C# Handling Exception in Task with await

I'm new to the async and await keywords in C# and I am using C# 6.0. What is the problem with my code? The DivideByZeroException does not get caught in the catch block. I read that in C# 5 and newer, exceptions can be handled easily with using await keyword surrounded by a try-catch block.
private async void button1_Click(object sender, EventArgs e)
{
try
{
Console.WriteLine("in try");
int result = await f(0);
textBox1.Text = result.ToString();
}
catch (Exception)
{
Console.WriteLine("in catch");
}
finally
{
Console.WriteLine("in finally");
}
}
Task<int> f(int x)
{
return Task<int>.Factory.StartNew(() =>
{
return 10 / x;
});
}
It is working in release, but since this is WebForms/WPF or WinForms app, it doesn't have console, so Console.WriteLine never prints anything. Replace:
Console.WriteLine("in catch");
with
textBox1.Text = "in catch";
This will work:
try
{
textBox1.Text += "in try";
int result = await f(0);
textBox1.Text = result.ToString();
}
catch (Exception)
{
textBox1.Text += "in catch";
}
finally
{
textBox1.Text += "in finally";
}

Check my SQL connection every second without freezing

First of all, I apologize for my English.
I have a method to verify my connection to SQL (TestConneccion), and I use a timer to verify it every second.
The problem is when I lose the connection, my application hangs while it tries to connect. I'm using task to avoid this, but I am new to C#.
I would really appreciate the help
public string testConeccion()
{
var archivo = "";
try
{
odb = DatabaseFactory.CreateDatabase("TESTCONECTION");
ocn = odb.CreateConnection();
if (ocn.State == ConnectionState.Closed)
{
ocn.Open();
}
ocn.Close();
archivo = "true";
}
catch (InvalidOperationException ex)
{
archivo = ex.Message;
}
catch (Exception ex)
{
archivo = ex.Message;
}
finally
{
ocn.Close();
}
return archivo;
}
private void timerMesas_Tick(object sender, EventArgs e)
{
Task<string> T1 = Task.Run<string>(() => oClasePublica.testConeccion());
if (T1.Result == "true")
{
btnEstado.Image = new System.Drawing.Bitmap(TOUCHREST.Properties.Resources.Status_32x32);
}
else
{
btnEstado.Image = new System.Drawing.Bitmap(TOUCHREST.Properties.Resources.Warning_32x32);
}
}
Make your timer tick handler async and await your task. This will run the method asynchronously and prevent the rest of your application from hanging while it runs.
private async void timerMesas_Tick(object sender, EventArgs e)
{
string T1 = await Task.Run<string>(() => oClasePublica.testConeccion());
if (T1 == "true")
{
btnEstado.Image = new System.Drawing.Bitmap(TOUCHREST.Properties.Resources.Status_32x32);
}
else
{
btnEstado.Image = new System.Drawing.Bitmap(TOUCHREST.Properties.Resources.Warning_32x32);
}
}
The ocn.Close() in the try code is not needed because the finally will do it. Also catch (InvalidOperationException ex) is not needed because catch (Exception) covers it.
You cannot do Task.Run and then immediately test the Result because the task has not yet finished! Normally you use Task.Wait(); however this will then block your main thread.
I suggest using a BackgroundWorker that continuously checks the connection and then reports it progress. This avoids the issue of changing the image on a non-UI thread.

Looking for an elegant way to get around "Cannot await in the body of a finally clause"

I have the following function:
private async Task DoSomething(NamespaceConnectionInfo nci)
{
var session = await m_sessionProvider.GetSessionAsync(nci);
SomeLegacySynchronousCode(session);
await m_sessionProvider.EndSessionAsync(session);
}
where EndSessionAsync logs and swallows any exception (like a good destructor).
The problem is that SomeLegacySynchronousCode may throw an exception and then the session leaks.
It is clear to me perfectly why the following code is illegal:
private async Task DoSomething(NamespaceConnectionInfo nci)
{
var session = await m_sessionProvider.GetSessionAsync(nci);
try
{
SomeLegacySynchronousCode(session);
}
finally
{
await m_sessionProvider.EndSessionAsync(session);
}
}
So, I am looking for an alternative that would be both correct and elegant.
Variant I
private async Task DoSomething(NamespaceConnectionInfo nci)
{
var session = await m_sessionProvider.GetSessionAsync(nci);
Exception exc = null;
try
{
SomeLegacySynchronousCode(session);
}
catch (Exception e)
{
exc = e;
}
await m_sessionProvider.EndSessionAsync(session);
if (exc != null)
{
// Wrap to preserve the original stack trace.
throw new AggregateException(exc);
}
}
Variant II
private Task DoSomething(NamespaceConnectionInfo nci)
{
return m_sessionProvider.GetSessionAsync(nci).ContinueWith(t =>
{
Task result = null;
try
{
SomeLegacySynchronousCode(t.Result);
}
finally
{
if (t.Exception == null)
{
result = m_sessionProvider.EndSessionAsync(t.Result);
}
}
return result;
}).Unwrap();
}
Neither are as elegant as the aforementioned illegal async/await version.
I am looking to improve over the two variants that I have proposed, because both are ugly, frankly.
Any ideas?
The commonly-accepted answer appears to be similar to your Variation 1:
You can move the logic outside of the catch block and rethrow the
exception after, if needed, by using ExceptionDispatchInfo.
static async Task f()
{
ExceptionDispatchInfo capturedException = null;
try
{
await TaskThatFails();
}
catch (MyException ex)
{
capturedException = ExceptionDispatchInfo.Capture(ex);
}
if (capturedException != null)
{
await ExceptionHandler();
capturedException.Throw();
}
}
This way, when the caller inspects the exception's StackTrace
property, it still records where inside TaskThatFails it was thrown.

Categories

Resources