C# Handling Exception in Task with await - c#

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";
}

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.

c# wpf change button content execute some code and then change it back

I have a simple wpf c# app that takes the text from the inputField tries to find some info there and returns the result into outputField.
Here is the code:
private void FindButton_Click(object sender, RoutedEventArgs e)
{
try
{
string parsed = string.Empty;
if (string.IsNullOrWhiteSpace(new TextRange(InputField.Document.ContentStart, InputField.Document.ContentEnd).Text));
{
OutputField.Document.Blocks.Clear();
MessageBox.Show("Empty input");
}
else
{
Parser nOb = new Parser(new TextRange(InputField.Document.ContentStart, InputField.Document.ContentEnd).Text);
string[] result = nOb.findAddresses();
if (result.Length == 0)
{
OutputField.Document.Blocks.Clear();
MessageBox.Show("Nothing found");
}
else
{
for (int i = 0; i < result.Length; i++)
{
parsed += result[i] + Environment.NewLine;
}
OutputField.Document.Blocks.Clear();
OutputField.Document.Blocks.Add(new Paragraph(new Run(parsed)));
MessageBox.Show("Success");
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
What I want to do is to change FindButton text from "Find" to "Searching..." and back when the search is completed.
I tried to add the following code just before try{}:
FindButton.Content = "Searching...";
FindButton.IsEnabled = false;
And changed it back after try{} to "Find" but it didn't work.
As I read somewhere I need to use async method here or threading.
I found a few solutions here and tried to add "async" to my function and also changed the code:
await Task.Run(() => {
//My code which is above
});
But it started returning the following error:
MS.Internal.PtsHost.UnsafeNativeMethods.PTS.SecondaryException
NullReferenceException
I'm completely new to these topics and don't know how to make it work. Please someone help.
Assuming that your findAddresses() method access UI elements and must be executed on the UI thread you could try to use Task.Delay to give the UI thread a chance to update the FindButton just before you kick of your operation. Try this:
private async void FindButton_Click(object sender, RoutedEventArgs e)
{
FindButton.Content = "Searching...";
FindButton.IsEnabled = false;
await Task.Delay(1);
try
{
string parsed = string.Empty;
if (string.IsNullOrWhiteSpace(new TextRange(InputField.Document.ContentStart, InputField.Document.ContentEnd).Text)) ;
{
OutputField.Document.Blocks.Clear();
MessageBox.Show("Empty input");
}
else
{
Parser nOb = new Parser(new TextRange(InputField.Document.ContentStart, InputField.Document.ContentEnd).Text);
string[] result = nOb.findAddresses();
if (result.Length == 0)
{
OutputField.Document.Blocks.Clear();
MessageBox.Show("Nothing found");
}
else
{
for (int i = 0; i < result.Length; i++)
{
parsed += result[i] + Environment.NewLine;
}
OutputField.Document.Blocks.Clear();
OutputField.Document.Blocks.Add(new Paragraph(new Run(parsed)));
MessageBox.Show("Success");
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
FindButton.Content = "Default";
FindButton.IsEnabled = true;
}

Catching errors with .NET Task Parallel Library

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;
});
}

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.

await async with Iron Python

For now I was using Parallel methods to check urls for 200 status code, but this was slow method. Now I'm trying to move my code to await/async methods but it doesn't working
private async void button1_Click(object sender, EventArgs e)
{
DateTime start = DateTime.Now;
var timerPostingSpeed = new Timer(state =>
{
TimeSpan elapsed = DateTime.Now - start;
string postingSpeed = string.Format("{0:0}",
finishedUrls * 60 / (int)elapsed.TotalSeconds);
UpdatingLabel(label1, postingSpeed);
}, null, 5000, 10000);
IEnumerable<string> urls = File.ReadLines("urls.txt");
var engine = Python.CreateEngine();
var scriptSource =
engine.CreateScriptSourceFromString(#"
if Open(__URL).Result:
print 1
");
await urls.ForEachAsync(20, async line =>
{
try
{
var adderEngine = new SpeedEngine();
// int zz = await adderEngine.Open(line);
// return;
ScriptScope scope = engine.CreateScope();
scope.SetVariable("__URL", line);
scope.SetVariable("Open",
new Func<string, Task<int>>(adderEngine.Open));
try
{
await scriptSource.Execute(scope);
}
catch (UnboundNameException une)
{
MessageBox.Show(une.Message,
msg.
MySeoBoxForm_startPostingToolStripButton_Click_Unbound_Name_Error,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (SyntaxErrorException see)
{
MessageBox.Show(
string.Format("{0}\nLine: {1}\nCode: {2}",
see.Message,
see.Line, see.GetCodeLine()),
msg.
MySeoBoxForm_startPostingToolStripButton_Click_Syntax_Error,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (MissingMemberException mme)
{
MessageBox.Show(mme.Message, "Missing Member",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (ArgumentTypeException ate)
{
MessageBox.Show(string.Format("{0}", ate.Message),
msg.
MySeoBoxForm_startPostingToolStripButton_Click_Syntax_Error,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (SystemExitException)
{
}
catch (Exception exc)
{
MessageBox.Show(string.Format("{0}", exc.Message),
msg.
MySeoBoxForm_startPostingToolStripButton_Click_Syntax_Error,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
MessageBox.Show(string.Format("{0}","OK"),
msg.
MySeoBoxForm_startPostingToolStripButton_Click_Syntax_Error,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception exc)
{
MessageBox.Show(string.Format("{0}", exc.Message),
msg.
MySeoBoxForm_startPostingToolStripButton_Click_Syntax_Error,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
Interlocked.Increment(ref finishedUrls);
numericUpDown1.Invoke(new MethodInvoker(delegate
{
numericUpDown1.Value++;
}));
}
});
timerPostingSpeed.Dispose();
}
}
public async Task<int> Open(string siteUrl)
{
Uri newUri;
if (!Uri.TryCreate(siteUrl, UriKind.Absolute, out newUri)) return 0;
_uri = _openUri = newUri;
_req = new HttpRequestMessage(HttpMethod.Get, _uri);
_response = await _httpClient.SendAsync(_req);
if (_response == null || !_response.IsSuccessStatusCode)
{
return 0;
}
return 1;
}
I need to use Iron Python - without it (when I uncomment await adderEngine.Open(line); return;) everything works ok. But with Iron Python my app stopped at *_response = await _httpClient.SendAsync(_req);* without errors. Also I noticed when I replace
await urls.ForEachAsync(20, async line =>
with:
await urls.ForEachAsync(1, async line =>
it's working
ForEachAsync: http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx
Any help?
If your Python code is calling Task.Result, and you're on a UI thread (as appears to be the case), you can cause a deadlock (I explain this fully on my blog). In short, the async method (Open) is trying to resume execution on the UI thread, but the UI thread is blocked by calling Result.
AFAIK, Python does not have async/await support, but you should be able to use ContinueWith (meh) or write some kind of bridge between Task and Twisted's Deferred (much cooler).

Categories

Resources