2012-05-22 80 views
11

我正在使用FirstChanceException事件記錄有關任何拋出異常的詳細信息。AppDomain.FirstChanceException和堆棧溢出異常

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

    throw new Exception("Exception thrown in main."); 
} 

這個按預期工作。但是,如果在事件處理程序中引發異常,則會發生堆棧溢出,因爲事件將以遞歸方式引發。

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

    throw new Exception("Exception thrown in main."); 
} 

如何處理事件處理程序中發生的異常?

編輯:

有幾個答案提示我包裹在一個try/catch塊的事件處理程序中的代碼,但是這並不工作,因爲該事件引發的異常可以處理了。

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

    throw new Exception("Exception thrown in main."); 
} 
+0

只需使用一個布爾領域,以防止遞歸。 –

+0

我不明白你爲什麼要這樣做。第一次機會例外處理。爲什麼你會拋出另一個呢? – leppie

+0

我不是故意投擲另一個。如果我試圖記錄該錯誤並且在嘗試記錄該信息時引發異常,會發生什麼情況? – nivlam

回答

-1

一般例外,你可以處理所有其他人一樣,但對於特別StackOverflowOutOfMemory例外,它們不能在.NET框架處理。

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

與.NET Framework 2.0版開始,StackOverflowException 對象不能被一個try-catch塊捕獲,並且相應的 過程默認情況下終止。因此,建議用戶 編寫代碼來檢測和防止堆棧溢出。例如, 如果您的應用程序依賴於遞歸,請使用計數器或狀態 條件來終止遞歸循環。

+0

我不想捕捉到一個stackoverflow異常。我正在尋找一種方法來防止它發生。 – nivlam

+0

@nivlam:爲了防止它發生,只是不要調用以*方式創建堆棧溢出的函數。你在尋找什麼解決方案? – Tigran

-1

我想增加另外try {} catch(){}塊中的異常處理程序將有助於內部異常

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."); 
} 
+1

這不起作用。在可以在catch塊中處理異常之前引發FirstChanceException事件。 – nivlam

-1

手柄手動如

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."); 
} 
0

您鏈接的MSDN文章對一些recommandations:

你必須處理髮生在該FirstChanceException事件的事件處理程序的所有異常。否則,遞歸引發FirstChanceException。這可能會導致應用程序堆棧溢出和終止。我們建議您將此事件的事件處理程序作爲受限執行區(CER)實施,以便在正在處理異常通知時保持與基礎結構相關的異常(如內存不足或堆棧溢出)影響虛擬機。

所以附上功能的try/catch塊內,塊之前調用PrepareConstrainedRegion避免OutOfMemory異常:http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx

編輯:好了,你還有遞歸問題,即使在try/catch塊。所以...我想你只需要調用不會拋出任何異常的安全代碼。該事件處理程序看起來相當危險,我建議僅將它用於調試目的。

+0

ASP.NET中的任何問題性能?我的** dump生產**爲我的應用程序_ASP.NET 4.6.1_。只有20分鐘有_7000個例外_(***第一次機會例外***)。我需要安全地記錄_first chance exceptions_以研究問題,而不會出現*** stackoverflow或outofmemory異常*** – Kiquenet

0

首先使用方法,而不是一個委託,因此該方法的名稱將被定義

然後使用Environment.StackTrace以檢查方法已經在堆棧跟蹤

這裏是一段代碼未經測試

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

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

    // handle 
} 

我覺得上面不會工作,因爲它會始終包含方法的名稱,但如果它出現次數大於1點時,你可以指望。 此外,檢查它在發佈模式下編譯時沒有內聯,在這種情況下,您遇到了問題

+0

當Environment.StackTrace屬性getter拋出異常時會發生什麼? – hvd

+0

爲什麼要扔? Doc(http://msdn.microsoft.com/en-us/library/system.environment.stacktrace.aspx)說它只能拋出一個ArgumentOutOfRangeException但我不能在這種情況下 – Fabske

+0

任何事情總是會拋出一個'OutOfMemoryException' 。這將觸發第一次機會異常,並試圖獲得另一個堆棧跟蹤,這也將失敗,因爲你內存不足。 – hvd

1

雖然它不是一個好方法,但在VB .NET中,您可以防止在FirstChanceException事件處理程序中使用「 On Error Resume Next「語句,來自VB 6.(我不確定C#是否有類似的內容)另外,您應該防止事件處理程序的遞歸,如here所述。以下是示例代碼,似乎按預期工作。

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 
4

這是爲我工作:

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; 
    } 
} 
+0

這確實是這樣做的正確方法,它應該被標記爲接受的答案。儘管如此,您可能需要增加代碼才能處理不同的應用程序,但除此之外,還是不錯的解決方案! – Abel

+0

不錯的解決方案,你節省了我的一天 –