I am sure I am doinig something wrong, but when I try this example of the new threading task exception handling I keep getting the exception unhandled by user code. The whole point of the code is to show an example of how to catch errors in tasks.
Link: Task Exception Example
static void Main(string[] args)
{
var task1 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("I'm bad, but not too bad!");
});
try
{
task1.Wait();
}
catch (AggregateException ae)
{
// Assume we know what's going on with this particular exception.
// Rethrow anything else. AggregateException.Handle provides
// another way to express this. See later example.
foreach (var e in ae.InnerExceptions)
{
if (e is MyCustomException)
{
Console.WriteLine(e.Message);
}
else
{
throw;
}
}
}
}
Most likely user error just not sure what (Using Visual Studio 2012);
From the page you cited:
Note
When "Just My Code" is enabled, Visual Studio in some cases will
break on the line that throws the exception and display an error
message that says "exception not handled by user code." This error is
benign. You can press F5 to continue and see the exception-handling
behavior that is demonstrated in these examples. To prevent Visual
Studio from breaking on the first error, just uncheck the "Just My
Code" checkbox under Tools, Options, Debugging, General.
Related
My code calls a WCF service that is current not running. So we should expect the EndPointNotFoundException. The using statement tries to Close() the faulted connection which causes a CommunicationObjectFaultedException which is excepted. This exception is caught in a try catch block surrounding the using block:
class Program
{
static void Main()
{
try
{
using (ChannelFactory<IDummyService> unexistingSvc = new ChannelFactory<IDummyService>(new NetNamedPipeBinding(), "net.pipe://localhost/UnexistingService-" + Guid.NewGuid().ToString()))
{
using (IClientChannel chan = (unexistingSvc.CreateChannel() as IClientChannel))
{
(chan as IDummyService)?.Echo("Hello");
}
}
}
catch (EndpointNotFoundException ex)
{
Console.WriteLine("Expected");
}
catch (CommunicationObjectFaultedException ex)
{
Console.WriteLine("Expected: caused by closing channel that has thrown EndPointNotFoundException");
}
}
}
Note the service EndPoint uses a fresh Guid so it will never have a service listening.
IDummyService is:
[ServiceContract]
interface IDummyService
{
[OperationContract]
string Echo(string e);
}
This causes the Visual Studio debugger (Visual Studio Professional 2017 15.4.1) to break with an "Exception Unhandled" popup:
The exception on which Visual Studio breaks is System.ServiceModel.CommunicationObjectFaultedException which is caught in the code.
Stepping to continue execution shows that catch(CommunicationObjectFaultedException ex) is reached. Using LinqPad to run the demo also shows that the exception is caught as expected.
I also tried explicitly (double) closing the channel instead of using the using-block:
class Program
{
static void Main()
{
try
{
using (ChannelFactory<IDummyService> unexistingSvc = new ChannelFactory<IDummyService>(new NetNamedPipeBinding(), "net.pipe://localhost/UnexistingService-" + Guid.NewGuid().ToString()))
{
IDummyService chan = null;
try
{
chan = unexistingSvc.CreateChannel();
chan.Echo("Hello");
}
catch (EndpointNotFoundException ex)
{
Console.WriteLine($"Expected: {ex.Message}");
}
finally
{
try
{
(chan as IClientChannel)?.Close();
}
catch (CommunicationObjectFaultedException ex)
{
Console.WriteLine($"Caused by Close: {ex.Message}");
}
}
}
}
catch (EndpointNotFoundException ex)
{
Console.WriteLine("Expected");
}
catch (CommunicationObjectFaultedException ex)
{
Console.WriteLine("Expected: caused by closing channel that has thrown EndPointNotFoundException");
}
}
}
This still causes the debugger to break on the Close statement.
My Exception Settings has System.ServiceModel.CommunicationObjectFaultedException unchecked. (When it is checked Visual studio breaks as expected and with the "Exception Thrown" dialog instead of the "Exception Unhandled" dialog).
When I enable "Options"\"Debugging"\"General"\"Enable Just My Code" the debugger does not break. However, I have async methods where the exception should leave my code and I later catch the exception when awaiting the Task. For these methods I need "Enable Just My Code" unchecked; see Stop visual studio from breaking on exception in Tasks.
With "Using the New Exception Helper" disabled (as suggested by Jack Zhai-MSFT) Visual Studio still breaks and it shows
The dialog provides some additional information:
The exception is not caught before it crosses a managed/native boundary.
I suspect that the using block probably introduces this managed/native boundary.
What causes the debugger to break by mistake and how to make the debugger not break neither or handled CommunicationObjectFaultedExceptions nor on later handler async exceptions?
The new Exception feature was in VS2017, we could disable debugging option "Use the New Exception Helper" under TOOLS->OPTION->Debugging->General which could provide you the old Exception messages, you could visit it.
The old Exception Message shows that the Exception crosses a managed/native boundary:
Check "Break when Exceptions cross AppDomain or managed/native boundaries" under TOOLS->OPTION->Debugging->General. Disable "Break when Exceptions cross AppDomain or managed/native boundaries" to avoid Visual Studio breaking on the OP's situation (be careful though since this also disables breaking on other situations where an exception crosses an AppDomain or managed/native boundary).
Close()-ing a Faulted IClientChannel causes a CommunicationObjectFaultedException:
public void Close(TimeSpan timeout)
{
...
switch (originalState)
{
case CommunicationState.Created:
case CommunicationState.Opening:
case CommunicationState.Faulted:
this.Abort();
if (originalState == CommunicationState.Faulted)
{
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
}
break;
...
}
...
}
-- (See CommunicationObject.Close(TimeSpan) line #299 in the .NET framework 4.7 reference source).
The using-block is translated to try { ... } finally { Dispose(); } and Dispose() calls Close() when the block is left. The proxy returned by CreateChannel() is implemented via RealProxy (src) and RemotingServices.CreateTransparentProxy() these proxy combine managed and unmanaged code, which might cause the exception crossing the boundary.
The combination of settings (in TOOLS->OPTIONS->Debugger->General):
☑ Break when Exceptions cross AppDomain or managed/native boundaries
☐ Enable Just My Code
Causes Visual Studio to break showing either: the new non-modal exception popup "Exception Unhandled":
or the modal dialog:
The CommunicationObjectFaultedException starts in 'Not My Code'; it crosses an managed/unmanaged or AppDomain boundary while still being in 'Not My Code'; and finally enters 'My Code' where it is handled by the catch-block (but Visual Studio has already halted the excuting at this point).
Since the exception starts in 'Not My Code' and remains there when crossing the boundary, selecting the option "Enable Just My Code" causes Visual studio to not break on the exception even when it crosses the AppDomain or managed/unmanaged boundary.
Deselecting "break when exceptions cross AppDomain or managed/native boundaries" also causes Visual Studio to not break on the exception.
This gives two solutions/workarounds
Choose a different combination of "Break when Exceptions cross AppDomain or managed/native boundaries" and "Enable Just My Code"
Do not use a using-block for the IClientChannel and check IClientChannel.State before Close()-ing. As is done in What is the best workaround for the WCF client `using` block issue?
Code sample:
using System;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
Console.WriteLine("Start");
Foo f = new Foo();
f.FooAsync();
}
public class Foo
{
public async void FooAsync()
{
try
{
await Task.Run(() =>
{
Console.WriteLine("Throwing");
throw new Exception();
});
}
catch (Exception)
{
Console.WriteLine("Caught");
}
}
}
}
The above code when run from C# fiddle or from the console on my PC prints:
Start
Throwing
Caught
C# Fiddle Example
However, when I run it from Visual Studio (F5 in debug mode), I get the following message:
I don't understand why I get "was not handled in user code" message from Visual Studio although running it from the console or C# fiddle is fine. Am I missing something obvious?
UPDATE
I've tried waiting on the task f.FooAsync().Wait(); in Main, but the exception is still reported as being unhandled (same error message).
First, what's special about this exception is that it's being thrown from Task.Run and for that scope, the exception really isn't handled by user-code.
The framework catches and stores the exception in the returned task for you to handle later, if you fail to do that it's an unobserved task exception (which in .Net 4.0 would've crashed the application).
The issue here is the "Enable Just My Code" feature in the settings. When the feature is turned on the debugger breaks on exceptions when you leave user-code and enter framework-code and at that point the exception really wasn't handled.
If you turn that feature off the debugger will not break on that exception as it will follow your code into the framework and see the exception being handled and stored in the task. The exception will then be re-thrown when you await the task and be handled by your code.
Since the handling that actually matters is the one being done by the framework, this is an even simpler example:
public static void Main()
{
Task.Run(() =>
{
throw new Exception();
});
Console.ReadLine();
}
With "Enable Just My Code" turned on the debugger will break on the exception, without it the debugger will not.
I have some strange problem here. Exception thrown by Task always not handled independently how can I try to handle it.
I try this:
http://msdn.microsoft.com/en-us/library/dd997415%28v=vs.110%29.aspx
private class MyCustomException : Exception
{
public MyCustomException(String message) : base(message)
{
}
}
public static void Main()
{
var task1 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("I'm bad, but not too bad!");
});
try
{
task1.Wait();
}
catch (AggregateException ae)
{
// Assume we know what's going on with this particular exception.
// Rethrow anything else. AggregateException.Handle provides
// another way to express this. See later example.
foreach (var e in ae.InnerExceptions)
{
if (e is MyCustomException)
{
Console.WriteLine(e.Message);
}
else
{
throw;
}
}
}
Console.Read();
}
this:
http://dotnetcodr.com/2014/02/11/exception-handling-in-the-net-task-parallel-library-with-c-the-basics/
this:
http://blogs.msdn.com/b/pfxteam/archive/2010/08/06/10046819.aspx
this:
var task = Task.Factory.StartNew(() => this.InitializeViewModel(myViewModel));
task.ContinueWith(o => MyErrorHandler(task.Exception), TaskContinuationOptions.OnlyOnFaulted);
and check a lot of other similar questions on StackOverflow. But It is always the same - exception is not handled. It is not handled on these primitive code snippets! I think it is some magic here...
I work on .Net Framework 4.0
Meanwhile single way to handle exception that works for me is:
Task.Factory.StartNew(() =>
{
try
{
//do something that thrown exception
}
catch (Exception)
{
}
});
If you run that example code in Visual Studio, you will indeed get the message MyCustomException was unhandled by user code and Visual Studio will break in that line.
That does not mean that your exception is really unhandled. It just means that, by default, Visual Studio breaks on exceptions which are not handled inside the Task. You can verify this by running your application without debugging (Ctrl-F5); you will note that your exception gets handled as expected.
This issue is described in more detail in the following SO question:
Stop visual studio from breaking on exception in Tasks
Microsoft Visual Studio debugging facilities for managed code have an option "Just My Code". This option enabled forces debugger to break in immediately when an exception leaves user code (Task delegate in your example) and enters non-user code (TPL internal in your example). This feature was designed before introduction of TPL to make .NET applications debugging more comfortable with looking only at the code you have written and ignore other code, such as system calls. Just My Code hides non-user code so that it does not appear in the debugger windows. When you step, the debugger steps through any non-user code but does not stop in it.
But now in fact "Just My Code" feature interfere with TPL implementation.
There are four ways to deal with this issue:
Run your code without debugging.
Just ignoring of the Visual Studio debugger message about unhanded exception by continuation of program execution.
Disabling of "Just My Code" option in the Microsoft Visual Studio. This variant is recommended by Microsoft guy Danny Shih from Parallel Computing Platform team (PFX Team) http://blogs.msdn.com/b/pfxteam/archive/2010/01/11/faq-the-debugger-does-not-correctly-handle-task-exceptions.aspx.
I have a class Dispatcher with a method Send as follows:
public class Dispatcher : IDispatcher {
public void Send(Order order) {
Type type = typeof(IOrderHandler<>).MakeGenericType(order.GetType());
IOrderHandler handler = (IOrderHandler)ObjectFactory.GetInstance(type);
try {
handler.Handle(order);
} catch (Exception exception) {
ILogger logger = ObjectFactory.GetInstance<ILogger>();
logger.Send(exception);
}
}
} // Send
I am handling orders and catching exceptions ...
When I am debugging I would like to still fire the exception.
How can I do this?
Thank You,
Miguel
Just add this line to your catch block:
if (System.Diagnostics.Debugger.IsAttached) throw;
You can add the following in your catch block:
#if DEBUG
throw;
#endif
So your code would look like:
try
{
handler.Handle(order);
}
catch (Exception exception)
{
ILogger logger = ObjectFactory.GetInstance<ILogger>();
logger.Send(exception);
#if DEBUG
throw;
#endif
}
If you want the exception notification in IDE during debugging in Release configuration, then use #Hans Passant's answer, because that will let you know about the exception for both Release and Debug configuration.
Well, based on the fact that you'd like the exception to still be thrown, but only when debugging, you could do this:
Open the Debug menu and choose Exceptions.
When the dialog loads, tick the check box next to Common Language Runtime Exceptions under the Thrown heading.
This will cause you to get a first chance exception. What that means is you'll be notified by the IDE, when debugging, and you'll get a chance to handle it before processing continues. This will actually let you see it before it even gets logged.
What's more, you can actually unselect exceptions you don't want with this approach because they are broken down by exception type underneath the Common Language Runtime Exceptions grouping.
More detail...
Go to Debug > Exception and check the CLR exceptions for "thrown", this will take you right there. alternatively place a breakpoint on the catch block.
I am running this test case using NUNIT and attaching the NUNIT to the Visual studio debugger (Debug ---> Attach to Process ---> Select nunit.exe).
I was expecting the statement "throw new Exception("Exception 1 occured!");"to move the control into the catch block but
the control does not jump to the "catch" but instead jumps to method2().
When I just run the nunit test case without attaching nunit.exe to the Visual Studio debugger the code behaves normally.
public void test()
{
try
{
method1();
if (condition1)
{
throw new Exception("Exception 1 occured!");
}
method2();
if (condition2)
{
throw new Exception("Exception 2 occured!");
}
method3();
if (condition3)
{
throw new Exception("Exception 3 occured!");
}
}
catch (Exception Ex) <---- Exceptions thrown above are caught here
{
logMessage(E.Message);
throw;
}
}
Visual Studio is probably set to break on all Exceptions instead of just uncaught Exceptions. So it stops when it detects that you threw the Exception. In certain cases, rather than appearing to break on the line that throws the exception, Visual Studio highlights the next line of code which was about to run.
If you continue to step through the code, you should see it go to the catch block next.