Exception in async/await not caught - c#

I do not understand why an exception thrown inside an async method is not caught when the await statement is surrounded by a try/catch, which becomes an unhandled exception crashing the app.
The reason for this exception is understood, I'm not expecting an answer for that. I was assuming the exception would be caught. I'm worried about the exception handling in the application not doing what is expected on future exceptions.
using Amazon.Lambda.Model;
InvokeResponse invokeResponse;
var lambdaRequest = new InvokeRequest {...};
try
{
var task = _awsLambdaClient.InvokeAsync(lambdaRequest);
invokeResponse = await task; <<== throws TaskCanceledException
}
catch (Exception e)
{
Log.Error(...);
return
}
C# environment is Mono, Xamarin.Android to be specific, though I imagine the same code compiled in a .NETCORE console app would repro as well, unless this is a bug in Mono which I doubt. I assume I'm misunderstanding something about exception handling.
UPDATE:
Tried the same code in a .NETCORE20 console application, and the TaskCanceledException is handled. So it's looking like a Mono/Xamarin.Android specific problem.
New Update: After being able to repro this for a few days, of course my repro stopped repro'ing and the exception is now caught in the Mono app too. Not really sure what happened.

Related

How can i manage exceptions from Client.PostAsync<T>? [duplicate]

I was hoping somebody could enlighten me a little bit on an issue I am facing in regards to async/await exception handling with HttpClient. I have written some code to illustrate, and it is being excecuted on both a Windows Phone 8 device and the emulator:
private async void SearchButton_Click(object sender, EventArgs e)
{
try
{
HttpClient client = new HttpClient();
System.Diagnostics.Debug.WriteLine("BEGIN FAULTY REQUEST:");
string response = await client.GetStringAsync("http://www.ajshdgasjhdgajdhgasjhdgasjdhgasjdhgas.tk/");
System.Diagnostics.Debug.WriteLine("SUCCESS:");
System.Diagnostics.Debug.WriteLine(response);
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine("CAUGHT EXCEPTION:");
System.Diagnostics.Debug.WriteLine(exception);
}
}
Tapping the button that invokes this function, produces the following output in the debugger console, the most interesting being the ones in bold:
BEGIN FAULTY REQUEST:
An exception of type 'System.Net.WebException' occurred in System.Windows.ni.dll and wasn't handled before a managed/native boundary
An exception of type 'System.Net.WebException' occurred in System.Windows.ni.dll and wasn't handled before a managed/native boundary
A first chance exception of type 'System.Net.Http.HttpRequestException' occurred in mscorlib.ni.dll
An exception of type 'System.Net.Http.HttpRequestException' occurred in mscorlib.ni.dll and wasn't handled before a managed/native boundary
CAUGHT EXCEPTION:
(and here it prints out the HttpRequestException)
Of course I am expecting an error in this case since the URL I am calling is nonsense. What I am not understanding here, is why the debugger reports that the exceptions are not handled, when the output simultaneously reports that the exception is caught. Also, the UI side of the app becomes much less responsive while the output is being printed, indicating that something is probably amiss.
Is this not the way to handle exceptions when working with async and await? I appreciate any input! Thanks.
As you are using HttpClient, try to use response.EnsureSuccessStatusCode();
Now HttpClient will throw exception when response status is not a success code.
try
{
HttpResponseMessage response = await client.GetAsync("http://www.ajshdgasjhdgajdhgasjhdgasjdhgasjdhgas.tk/");
response.EnsureSuccessStatusCode(); // Throw if not a success code.
// ...
}
catch (HttpRequestException e)
{
// Handle exception.
}
ORIGINAL SOURCE OF THE CODE: http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client
This is an artifact of the debugger. It's determining that an exception is "uncaught" because it's not caught yet. In this case this is expected behavior.
You are handling the exceptions correctly.
The debugger is telling you that this exception is first chance. When a debugger is attached to your process it gets notified for every exception that is thrown and then based on how the debugger has been configured it will decide what to do with it. You can go through What is first chance exception? for more details.
On a side note, catch specific exceptions only so that you understand which exceptions you are expecting and why.

Roslyn scripting engine does not throw runtime exception when used as delegate

I run into troubles using the Roslyn Scripting Engine. I get no exception handling when I run a script within a delegation.
Test that works as expected:
string script = #"var a=0; var b=2/a;";
var runner = CSharpScript.Create<object>(script);
var errors = runner.Compile();
Assert.IsTrue(errors.IsEmpty);
try
{
runner.RunAsync();
Assert.Fail("Where is the exception");
}
catch (System.Exception)
{
// everything is OK! Error thrown...
}
Result: No Assertion. The Exception was thrown.
Here's the text using a delegate object:
Unittest:
string script = #"var a=0; var b=2/a;";
var runner = CSharpScript.Create<object>(script);
var errors = runner.Compile();
var delegat = runner.CreateDelegate();
Assert.IsTrue(errors.IsEmpty);
try
{
delegat();
Assert.Fail("Where is the exception?");
}
catch (System.DivideByZeroException)
{
// everything is OK! Error thrown...
}
I got the fail message and no exception was thrown.
We cache the delegates to speed up the compilation and during a test we see that runtime exceptions are not thrown. So I wrote the test to reproduce this situation.
I can't find any hint in the docs which describes that there are no exceptions thrown during the invoke.
Can someone give me a pointer or a hint why this happens?
There are two issues with your code:
In the first version, you're catching Exception, which means that when the Assert.Fail is reached and throws AssertionException, that exception is then caught and ignored.
This means that there is no difference between RunAsync and delegate here, neither of them throws DivideByZeroException.
Both RunAsync and the ScriptRunner<T> delegate return Task. That means to actually wait for them to complete or to observe any exceptions, you need to use await. Once you do that, you will see the DivideByZeroException that you're expecting.
Your Main finishes execution before the scheduler gets a chance to invoke delegat. It is a task that will run asynchronously. You can see that when you inspect it in the debugger:
To force execution inside the scope of the try...catch, you can use this:
try
{
delegat().Wait();
}
catch(System.AggregateException ex)
{
/* the inner exception of ex will be your DivideByZeroException */
}
The correct type of exception to expect in this case is the AggregateException, see here why.
A solution with await is also possible:
await delegat();
but this will compile only when the containing method can be marked async which is not necessarily what you want (show more of the calling code to clarify).

Why do my C# unit tests for exceptions fail if I use try/catch?

I'm using C# with nUnit to unit test my project and I'm trying to write some unit tests that ensure a certain Exception is called but my tests keep failing. After a lot of testing to work out the issue, I managed to identify the cause of it and created a small code example that shows my issuew below.
My unit test code:
[Test]
public void TestExceptionIsRaised()
{
var ex = Assert.Throws<UnauthorizedAccessException>(() => TestExceptionMethod());
StringAssert.Contains("Attempted to perform an unauthorized operation", ex.Message);
}
My method with no error checking:
public void TestExceptionMethod()
{
throw new UnauthorizedAccessException();
}
Now if I run that unit test with the above method... it throws the exception, nUnit detects it and the test passes. However, this code is a problem because it has no error handling and will crash if I release it like this.
So to solve that problem, I add some error handling into my method like this:
public void TestExceptionMethod()
{
try
{
throw new UnauthorizedAccessException();
}
catch (UnauthorizedAccessException ex)
{
// Do something about the error
}
}
But now when I run the unit test it fails with this error:
Expected: System.UnauthorizedAccessException
But was: null
So rather than having to choose between a unit test or proper error handling, I tried to re-throw the error like this:
public void TestExceptionMethod()
{
try
{
throw new UnauthorizedAccessException();
}
catch (UnauthorizedAccessException ex)
{
// Do something about the error
throw;
}
}
Finally, everything now works. The unit test passes every time. And my method can still catch the error and do something about it.
However from what I've heard it isn't good practice to keep re-throwing errors like this??? So I'm just wondering is my solution "correct"? Or is there a better way of unit testing for an exception without having to remove the try/catch blocks from the original method?
However from what I've heard it isn't good practice to keep
re-throwing errors like this???
There is nothing wrong with re-throwing exceptions. It's actually a best practice to re-throw the exception after your application runs some logging code without recovering your application state.
Or is there a better way of unit testing for an exception without
having to remove the try/catch blocks from the original method?
I'm not sure I understand what you mean. But if you expect an exception thrown from your method, there must be an exception for your test to pass no matter it's thrown directly or re-thrown. If you try/catch like this:
public void TestExceptionMethod()
{
try
{
throw new UnauthorizedAccessException();
}
catch (UnauthorizedAccessException ex)
{
// Do something about the error
}
}
The test will fail for sure because the exception is swallowed. The test cannot detect there was an exception inside the method.
Translating your test into English you are saying:
"I expect the method TestExceptionMethod to throw a
UnauthorizedAccessException. The message of which will contain a
string with more details."
By not throwing the exception this test will never pass. If you don't want the exception to be thrown you need to change your test. If you do want the exception to be thrown, what you're doing is correct.
Is this correct?
It depends. If what you're doing is an exceptional issue, then throw an exception. Let the program crash. Fix the bug.
On the other hand if this is something that is to be expected such as bad user input, boundary conditions, handle it if you can. If you cannot recover from the problem then throw an exception.
Exception handling done poorly can make debugging more difficult especially when the exception is swallowed, or when a new exception instance is created and thrown losing the stack trace of the original exception. Sometimes the latter is desirable when you need a more abstract exception higher up the call stack, in which case you can add the original exception as an inner exception to keep access to the stack trace.

How to find exceptions thrown by OpenReadAsync method

Consider the following code:
using (IRandomAccessStream stream = await storageFile.OpenReadAsync())
{
using (DataReader dataReader = new DataReader(stream))
{
uint length = (uint)stream.Size;
await dataReader.LoadAsync(length);
txtbox.Text = dataReader.ReadString(length);
}
}
storageFile.OpenReadAsync may throw exception, System.IO.FileNotFoundException is one possible exception type. MSDN topic StorageFile.OpenReadAsync http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.storagefile.openreadasync doesn't contain list of exception types thrown by this method. How can I find this information from documentation? I can catch an Exception type, but this is poor programming practice.
In cases where it is impossible to find all list of exceptions I usually use approach from VS SDK ErrorHandler.IsCriticalException:
try
{
// ...
}
catch(Exception e)
{
if (ErrorHandler.IsCriticalException(e))
{
throw;
}
// log it or show something to user
}
You can decompile the Microsoft.VisualStudio.Shell.11.0.dll to find the list of exceptions, which ErrorHandler defines as Critical:
StackOverflowException
AccessViolationException
AppDomainUnloadedException
BadImageFormatException
DivideByZeroException
In the case of Windows Runtime I think that it will be good also to verify some of the HResult values in Exception, like E_OUTOFMEMORY, E_ABORT, E_FAIL, and maybe something else.
Also I found that BugSense is awesome help for logging exceptions. I use it not only for unhandled exception, but also for situations like this, where I have no idea what this method can throw. It allows to send custom logging (including exceptions) with BugSenseHandler.Instance.LogException, so I just collect information about different kind of exceptions (including exceptions with some unexpected HResult) and make some improvements for my app in each release.

How to fix "'System.AggregateException' occurred in mscorlib.dll"

I'm receiving an unhandled exception while debugging, and the program stops executing. The debugger doesn't show me the line so I don't know what to fix.
An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll
Additional information: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.
Cannot obtain value of local or argument '<this>' as it is not available at this instruction pointer, possibly because it has been optimized away. System.Threading.Tasks.TaskExceptionHolder
How can I troubleshoot this problem?
I also found this question which is pretty similar.
As the message says, you have a task which threw an unhandled exception.
Turn on Break on All Exceptions (Debug, Exceptions) and rerun the program.
This will show you the original exception when it was thrown in the first place.
(comment appended): In VS2015 (or above). Select Debug > Options > Debugging > General and unselect the "Enable Just My Code" option.
You could handle the exception directly so it would not crash your program (catching the AggregateException). You could also look at the Inner Exception, this will give you a more detailed explanation of what went wrong:
try {
// your code
} catch (AggregateException e) {
}
The accepted answer will work if you can easily reproduce the issue. However, as a matter of best practice, you should be catching any exceptions (and logging) that are executed within a task. Otherwise, your application will crash if anything unexpected occurs within the task.
Task.Factory.StartNew(x=>
throw new Exception("I didn't account for this");
)
However, if we do this, at least the application does not crash.
Task.Factory.StartNew(x=>
try {
throw new Exception("I didn't account for this");
}
catch(Exception ex) {
//Log ex
}
)
In my case I ran on this problem while using Edge.js — all the problem was a JavaScript syntax error inside a C# Edge.js function definition.

Categories

Resources