20

I'm using the FirstChanceException event to log details about any thrown exceptions.

static void Main(string[] args)
{
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
        {
            Console.WriteLine("Inside first chance exception.");
        };
    
    throw new Exception("Exception thrown in main.");
}

This works as expected. But if an exception is thrown inside the event handler, a stack overflow will occur since the event will be raised recursively.

static void Main(string[] args)
{
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
        {
            throw new Exception("Stackoverflow");
        };
    
    throw new Exception("Exception thrown in main.");
}

How do I handle exceptions that occur within the event handler?

Edit:

There's a few answers suggesting that I wrap the code inside the event handler in a try/catch block, but this doesn't work since the event is raised before the exception can be handled.

static void Main(string[] args)
{
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
        {
            try
            {
                throw new Exception("Stackoverflow");
            }
            catch
            {
            }
        };
    
    throw new Exception("Exception thrown in main.");
}
spaleet
  • 838
  • 2
  • 10
  • 23
nivlam
  • 3,223
  • 4
  • 30
  • 39
  • 1
    Just use a bool field to prevent recursion. – Hans Passant May 22 '12 at 07:09
  • I dont understand why you would want this. First chance exceptions are handled. Why on earth would you throw another one? – leppie May 22 '12 at 07:13
  • I'm not intentionally throwing another one. What happens if I'm trying to log that error and an exception is thrown while I'm trying to log that information? – nivlam May 22 '12 at 07:14
  • @nivlam You shouldn't be logging first-chance exceptions in the first place. They're not errors if they're handled properly. –  May 22 '12 at 07:16
  • This is for debugging purposes to find exceptions that are swallowed. – nivlam May 22 '12 at 07:16
  • 1
    @nivlam In that case, it would be much easier to use a debugger. It would probably even be easier to *create* a simple debugger that does nothing more than log first-chance exceptions. –  May 22 '12 at 07:18

7 Answers7

18

This is working for me:

private volatile bool _insideFirstChanceExceptionHandler;    

// ...

AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;

// ...

private void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs args)
{
    if (_insideFirstChanceExceptionHandler)
    {
        // Prevent recursion if an exception is thrown inside this method
        return;
    }

    _insideFirstChanceExceptionHandler = true;
    try
    {
        // Code which may throw an exception
    }
    catch
    {
        // You have to catch all exceptions inside this method
    }
    finally
    {
        _insideFirstChanceExceptionHandler = false;
    }
}
ayhjar
  • 301
  • 2
  • 6
  • This is indeed the right way of doing this, it should be marked the accepted answer. You may have to augment the code to take care of different appdomains though, but otherwise, nice solution! – Abel Dec 10 '15 at 11:46
  • nice solution, you saved my day – Dika Arta Karunia Jan 10 '18 at 14:33
  • @ayhjar has 91 reputation. And this is one of the best answers on SO. Well done Mr. Sleeperpants. You should participate more! – P.Brian.Mackey Dec 10 '18 at 20:05
  • 2
    If two exceptions happen at once, isn't this going to just ignore the second one and return? Or is the bool thread specific because its volatile or something? – Joe Phillips Oct 23 '19 at 19:43
  • Are there any way to know whether the exception was gracefully handled by try/catch block when using firstchanceexception? – Furkan Gözükara Feb 11 '20 at 07:31
  • [ThreadStatic] private bool _insideFirstChanceExceptionHandler; – Jannes May 19 '20 at 12:26
1

Eventhough it is not a good way, in VB .NET you can prevent exception firing inside FirstChanceException event handler using "On Error Resume Next" statement, coming from VB 6. (I am not sure if C# has something similar) Additionally, you should prevent recursion on the event handler as mentioned here. Following is the sample code, seems to work as expected.

Sub Main(args As String())
    AddHandler AppDomain.CurrentDomain.FirstChanceException, AddressOf FirstChanceExceptionEventHandler
    Throw New Exception("Exception thrown in main.")
End Sub

Private Sub FirstChanceExceptionEventHandler(ByVal source As Object, ByVal e As FirstChanceExceptionEventArgs)
    On Error Resume Next

    Dim frames As StackFrame() = New StackTrace(1).GetFrames()
    Dim currentMethod As MethodBase = MethodBase.GetCurrentMethod()
    If frames IsNot Nothing AndAlso frames.Any(Function(x) x.GetMethod() = currentMethod) Then
        Return
    Else
        Throw New Exception("Stackoverflow")
    End If
End Sub
aykutbulca
  • 11
  • 2
0

The MSDN article you linked makes a few recommandations:

You must handle all exceptions that occur in the event handler for the FirstChanceException event. Otherwise, FirstChanceException is raised recursively. This could result in a stack overflow and termination of the application. We recommend that you implement event handlers for this event as constrained execution regions (CERs), to keep infrastructure-related exceptions such as out-of-memory or stack overflow from affecting the virtual machine while the exception notification is being processed.

So enclose your function inside a try/catch block, and call PrepareConstrainedRegion before the block to avoid OutOfMemory exceptions: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx

Edit: Well, you still have the recursion issue even with the try/catch block. So... I guess you just have to call only safe code that won't throw any exception. That event handler seems quite dangerous, I'd recommend to use it only for debugging purpose.

Kevin Gosse
  • 38,392
  • 3
  • 78
  • 94
  • Any issues performance in ASP.NET ? I have a **dump production** for my application _ASP.NET 4.6.1_. There are _7000 exceptions_ (***first chance exceptions***) in only 20 minutes. I need log _first chance exceptions_ safely for study the problem, without get ***stackoverflow or outofmemory exceptions*** – Kiquenet Mar 02 '16 at 11:42
0

First use a method instead of a delegate, so the method name will be defined

Then use Environment.StackTrace to check if the method is already in the stacktrace

Here is a piece of code untested:

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.FirstChanceException += handleFirstChanceException;
} 

private void handleFirstChanceException(object sender, EventArgs eventArgs)
{
    if (Environment.StackTrace.Contains("handleFirstChanceException"))
        return;

    // handle
}

I think the above will not work because it'll always contains the method name, but you can count if it appear more than 1 time. Also, check that it's not inlined when you compile in Release mode, in this case you're in trouble

Fabske
  • 2,106
  • 18
  • 33
  • What happens when the `Environment.StackTrace` property getter throws an exception? –  May 22 '12 at 14:13
  • Why should it throw ? Doc (http://msdn.microsoft.com/en-us/library/system.environment.stacktrace.aspx) say it can only throw an ArgumentOutOfRangeException but I couldn't in which case – Fabske May 22 '12 at 17:04
  • Anything can always throw an `OutOfMemoryException`. Which will trigger a first-chance exception, and attempt to get another stack trace, which will also fail, since you're out of memory. –  May 22 '12 at 17:43
  • Indeed, but if your application throw an OutOfMemoryException, it's already ready to crash ... so instead of crashing with OutOfMemory, it'll crash with StackOverflow – Fabske May 23 '12 at 06:52
  • 1
    I'm not a fan of "it's already going wrong, so there's no problem making it worse" arguments, but there are other exceptions `Exception.StackTrace` might give too. Like you, I have no idea when `ArgumentOutOfRangeException` might be thrown, but the list in the documentation is not an exhaustive list. It doesn't list the potential `SecurityException` either, for example. In addition, I see no reason for assuming `Environment.StackTrace` doesn't sometimes internally throw and catch exceptions, which would again trigger the `FirstChanceException` event. –  May 23 '12 at 07:50
  • And something I totally missed: wouldn't it be better to check the stack trace of the thrown exception, rather than the current call stack? –  May 23 '12 at 07:51
  • Are there any way to know whether the exception was gracefully handled by try/catch block when using firstchanceexception? – Furkan Gözükara Feb 11 '20 at 07:31
-2

In general exception you can handle like all others, but what about in particular StackOverflow and OutOfMemory exception, they can not be handled in .NET Framework.

Look here: How do I prevent and/or handle a StackOverflowException? (C#)

Starting with the .NET Framework version 2.0, a StackOverflowException object cannot be caught by a try-catch block and the corresponding process is terminated by default. Consequently, users are advised to write their code to detect and prevent a stack overflow. For example, if your application depends on recursion, use a counter or a state condition to terminate the recursive loop.

Community
  • 1
  • 1
Tigran
  • 61,654
  • 8
  • 86
  • 123
  • I'm not looking to catch a stackoverflow exception. I'm looking for a way to prevent it from happening. – nivlam May 22 '12 at 06:54
  • @nivlam: to prevent it happening just do not call the function that creates stack overflow in a *way* you call it. What solution are you searching for, so?? – Tigran May 22 '12 at 06:55
-3

I think adding another try {} catch (){} block in the exception handler would help

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => 
    { 
        try {
            throw new Exception("Stackoverflow"); 
        } catch (Exception e)
        {
           // Do something very simple not throwing an exception...
        }
    }; 

    throw new Exception("Exception thrown in main."); 
} 
MichelZ
  • 4,214
  • 5
  • 30
  • 35
  • 2
    This doesn't work. The FirstChanceException event is raised before the exception can be handled in the catch block. – nivlam May 22 '12 at 06:56
-3

Handle inside exceptions manually e.g.

static void Main(string[] args) {
     AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
     {
         try{
         throw new Exception("Stackoverflow");} catch (Exception ex){/*manual handle*/}
     };
      throw new Exception("Exception thrown in main.");
 } 
Yasser Zamani
  • 2,380
  • 21
  • 18