2012-05-22 3 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."); 
} 

Как обрабатывать исключения, возникающие в обработчике событий?

Edit:

Там же несколько ответов предполагающих, что я обернуть код внутри обработчика событий в Try/поймать блок, но это не работает, так как событие вызывается перед тем, исключение может быть обработано.

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

В общем неприменении вы можете справиться, как и все другие, но что, в частности, StackOverflow и OutOfMemory исключения, они не могут быть обработаны в .NET Framework.

Посмотрите здесь: How do I prevent and/or handle a StackOverflowException? (C#)

Начиная с .NET Framework версии 2.0, StackOverflowException объект не может быть пойман примерки поймать блока и соответствующий процесс завершается по умолчанию. Следовательно, пользователям рекомендуется указать свой код для обнаружения и предотвращения переполнения стека. Например, , если ваше приложение зависит от рекурсии, используйте счетчик или состояние условие для завершения рекурсивного цикла.

+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

Это не работает. Событие FirstChanceException возникает до того, как исключение может быть обработано в блоке catch. – nivlam

-1

Handle внутри исключений вручную, например,

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/поймать блока и вызовите PrepareConstrainedRegion перед блоком, чтобы избежать OutOfMemory исключения: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx

Edit: Ну, вы все еще есть проблемы рекурсии даже при попытке/блок блокировки. Итак ... Думаю, вам просто нужно вызвать только безопасный код, который не будет вызывать никаких исключений. Этот обработчик событий кажется довольно опасным, я бы рекомендовал использовать его только для целей отладки.

+0

Какие-либо проблемы производительности в ASP.NET? У меня есть ** свалка ** для моего приложения _ASP.NET 4.6.1_. Есть _7000 исключений_ (*** первые случайные исключения ***) всего за 20 минут. Мне нужно log_first chance exceptions_ безопасно для изучения проблемы, не получая *** stackoverflow или outofmemory exceptions *** – Kiquenet

0

Сначала используйте метод вместо делегата, так что имя метода будет определяться

Затем используйте Environment.StackTrace, чтобы проверить, если этот метод уже в 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 раз. Кроме того, убедитесь, что он не встроен при компиляции в режиме Release, в этом случае у вас есть проблемы

+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

приятное решение, вы спасли мой день –

Смежные вопросы