2012-05-22 18 views
11

Używam zdarzenia FirstChanceException do rejestrowania szczegółów dotyczących zgłaszanych wyjątków.Wyjątek AppDomain.FirstChanceException i przepełnienie stosu

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

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

To działa zgodnie z oczekiwaniami. Ale jeśli zostanie zgłoszony wyjątek do obsługi zdarzenia, wystąpi przepełnienie stosu, ponieważ zdarzenie zostanie podniesione rekursywnie.

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

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

Jak radzić sobie z wyjątkami występującymi w ramach obsługi zdarzeń?

Edit:

Jest kilka odpowiedzi sugerujące, że zawinąć kod wewnątrz procedury obsługi zdarzenia w bloku try/catch, ale to nie działa, ponieważ zdarzenie jest wywoływane przed Wyjątkiem mogą być obsługiwane.

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

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

Wystarczy użyć pola bool aby zapobiec rekursji. –

+0

Nie rozumiem, dlaczego chcesz tego. Obsługiwane są wyjątki pierwszej szansy. Dlaczego, na Boga, rzuciłbyś jeszcze jednego? – leppie

+0

Nie celowo wyrzucam innego. Co się stanie, jeśli próbuję zarejestrować ten błąd i zostanie zgłoszony wyjątek podczas próby zarejestrowania tych informacji? – nivlam

Odpowiedz

-1

W ogólnym wyjątku można obsługiwać podobnie jak wszystkie inne, ale co w szczególności StackOverflow i OutOfMemory wyjątkiem, że nie mogą być obsługiwane w .NET Framework.

Spójrz tutaj: How do I prevent and/or handle a StackOverflowException? (C#)

Począwszy od wersji .NET Framework 2.0, StackOverflowException obiekt nie może zostać złapany przez blok try-catch a odpowiadający proces jest zakończony domyślnie. W związku z tym użytkownikom zaleca się napisanie ich kodu w celu wykrycia przepełnienia stosu i zapobieżenia temu. Na przykład: , jeśli twoja aplikacja zależy od rekursji, użyj warunku lub stanu, aby zakończyć pętlę rekurencyjną.

+0

Nie chcę złapać wyjątku stackoverflow. Szukam sposobu, aby temu zapobiec. – nivlam

+0

@nivlam: aby temu zapobiec, po prostu nie wywołuj funkcji, która tworzy przepełnienie stosu w * sposób * nazywasz to. Jakie rozwiązanie szukasz, więc? – Tigran

-1

myślę dodanie innego try {} catch(){} blok programu obsługi wyjątków pomogłoby

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

To nie działa. Zdarzenie FirstChanceException jest wywoływane, zanim wyjątek może zostać obsłużony w bloku catch. – nivlam

-1

uchwyt wewnątrz wyjątkami ręcznie np

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

W artykule MSDN jesteś połączony sprawia, że ​​kilka zalecenia,:

Musisz obsłużyć wszystkie wyjątki, które występują w obsługi zdarzeń dla zdarzenia FirstChanceException. W przeciwnym razie wyjątek FirstChanceException jest rekursywnie podnoszony. Może to spowodować przepełnienie stosu i zakończenie aplikacji. Zaleca się wdrożenie procedur obsługi zdarzeń dla tego zdarzenia jako regionów o ograniczonych wykonaniach (CER), aby wyjątki związane z infrastrukturą, takie jak brak pamięci lub przepełnienie stosu, mogły wpływać na maszynę wirtualną podczas przetwarzania powiadomienia o wyjątku.

Więc dołączyć swoją funkcję wewnątrz bloku try/catch, i nazywają PrepareConstrainedRegion przed blokiem, aby uniknąć OutOfMemory wyjątki: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx

EDIT: Cóż, nadal masz problem rekurencji nawet z try/blok catch. Więc ... Myślę, że musisz tylko wywołać tylko bezpieczny kod, który nie rzuci żadnego wyjątku. Ten program obsługi zdarzeń wydaje się dość niebezpieczny, zalecam go używać tylko do celów debugowania.

+0

Czy występują jakieś problemy w ASP.NET? Mam ** produkcję zrzutu ** dla mojej aplikacji _ASP.NET 4.6.1_. Istnieje _7000 exceptions_ (*** wyjątki pierwszej szansy ***) w zaledwie 20 minut. Potrzebuję zalogować _pierwszy przypadek wyjątków_ bezpiecznie do zbadania problemu, bez get *** stackoverflow lub outofmemory wyjątki *** – Kiquenet

0

najpierw użyć metody zamiast delegata, więc nazwa metoda zostanie zdefiniowany

Następnie użyj Environment.StackTrace aby sprawdzić, czy metoda jest już w stacktrace

Oto fragment kodu niesprawdzone:

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

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

    // handle 
} 

Myślę, że powyższe nie zadziała, ponieważ będzie ona zawsze zawiera nazwę metody, ale można liczyć, jeśli pojawi się więcej niż 1 raz. Sprawdź także, czy nie jest on wstawiony podczas kompilacji w trybie Release, w tym przypadku masz kłopoty.

+0

Co się dzieje, gdy getter właściwości 'Environment.StackTrace' zgłasza wyjątek? – hvd

+0

Dlaczego powinien on rzucać? Doc (http://msdn.microsoft.com/en-us/library/system.environment.stacktrace.aspx) mówi, że może tylko wywołać ArgumentOutOfRangeException, ale nie mógłbym w takim przypadku. – Fabske

+0

Wszystko może zawsze wywołać 'OutOfMemoryException' . Co wywoła wyjątek pierwszej szansy i spróbuje uzyskać kolejny ślad stosu, który również się nie powiedzie, ponieważ brakuje Ci pamięci. – hvd

1

Mimo że nie jest to dobry sposób, w VB .NET można zapobiec uruchamianiu wyjątków w ramach obsługi zdarzeń FirstChanceException za pomocą " On Error Resume Next ", pochodząca z VB 6. (Nie jestem pewien, czy C# ma coś podobnego) Dodatkowo, powinieneś zapobiec rekursji na module obsługi zdarzeń, jak wspomniano here. Poniżej znajduje się przykładowy kod, wydaje się działać zgodnie z oczekiwaniami.

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

To działa dla mnie:

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

Jest to rzeczywiście właściwy sposób robienia tego, powinien być oznaczony zaakceptowaną odpowiedzią. Być może będziesz musiał rozszerzyć kod, aby zająć się różnymi aplikacjami, ale poza tym, fajne rozwiązanie! – Abel

+0

fajne rozwiązanie, uratowałeś mój dzień –

Powiązane problemy