Как правильно обрабатывать (регистрировать) пользовательские исключения?

#c# #.net #exception #exception-handling

#c# #.net #исключение #обработка исключений

Вопрос:

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

 [Serializable]
public class CustomException : Exception
{
    public CustomException() { }
    public CustomException(string message) : base(message) { }
    public CustomException(string message, Exception inner) : base(message, inner) { }
    protected CustomException(
      System.Runtime.Serialization.SerializationInfo info,
      System.Runtime.Serialization.StreamingContext context)
        : base(info, context) { }
}
  

Создание исключения:

 CustomException ex = new CustomException("Here is a new custom exception! ");
LogError(ex);
  

Метод регистрации исключений (пользовательских и других!):

 public static void LogError(Exception ex)
{
    //Saving exception messages, inner exceptions etc
    //...
}
  

В этом случае ex.Stacktrace пользовательского исключения имеет значение null при его регистрации!

Я полагаю, причина в том, что метод ведения журнала (который пытается быть методом общего назначения) принимает объект исключения в качестве параметра, а не CustomException (?). Каков правильный способ создания метода ведения журнала, поскольку перегрузка его различными типами исключений кажется немного нелогичной?

Комментарии:

1.но Exception имеет StackTrace свойство, которое не расширяется CustomException msdn.microsoft.com/en-us/library/system.exception.aspx

2. @Jodrell: О чем ты говоришь? StackTrace отлично работает для всех исключений

3. @jgauffin: вот что я имею в виду, все исключения StackTrace унаследованы от Exception so, утверждение «Я полагаю, причина в том, что метод ведения журнала (который пытается быть методом общего назначения) принимает объект исключения в качестве параметра, а не CustomException (?).» Должно быть, неверно.

4. @Jodrell: ах, хорошо. Я запутался в its not extended

Ответ №1:

Я полагаю, причина в том, что метод ведения журнала (который пытается быть методом общего назначения) принимает объект исключения в качестве параметра, а не CustomException (?)

Неверно. Это значение равно нулю, поскольку вы на самом деле не создавали исключение, а просто создали его.

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

Ответ №2:

Вы можете использовать:

 public static void LogError<T>(T exception)
{
  // Serialize the exception here and write to log
}
  

Обратите внимание, что вы можете просто использовать любой объект здесь в сочетании с удобочитаемым форматом сериализации (т. Е. в формате Json). Затем вы можете просто зарегистрировать сериализованное представление объекта, где все общедоступные поля / свойства будут сохранены.

Обратите внимание, что вам также понадобится throw / catch для построения stacktrace для вас.

Комментарии:

1. Пожалуйста, объясните, почему универсальный метод будет лучше, чем тот, который используется Exception в качестве аргумента. Я не понимаю.

2. Я не хотел ограничивать регистратор только Exception объектами. Вы можете возразить, что я мог бы использовать ‘object’ в качестве аргумента, но мне нравится оставаться строго типизированным при использовании сериализации / десериализации.

3. Я не вижу никаких преимуществ наличия строго типизированных объектов во время сериализации, поскольку большинство сериализаторов object тоже работают.

Ответ №3:

Создайте CustomException экземпляр перед его регистрацией. Среда выполнения заполнит информацию о трассировке стека

Ответ №4:

  1. Регистрируйте исключения в блоке catch
  2. Проверьте уровень ведения журнала и регистрируйте только сообщение или полную информацию об исключении.

Например, мы используем методы расширения для TraceSource для регистрации исключений:

 public static void TraceException(this TraceSource traceSource, Exception ex)
{
    traceSource.TraceException(string.Empty, ex);
}

public static void TraceException(this TraceSource traceSource, string comment, Exception ex)
{
    if (!string.IsNullOrWhiteSpace(comment))
        comment  = "rn";

    traceSource.TraceEvent(TraceEventType.Error, (int)TraceEventType.Error,
            comment   "ExceptionType: {0} rn ExceptionMessage: {1}", ex.GetType(), ex.Message);

    if (traceSource.Switch.Level == SourceLevels.Verbose ||
        traceSource.Switch.Level == SourceLevels.All)
    {
        traceSource.TraceEvent(TraceEventType.Verbose, 0, ex.ToString());
    }
}
  

Использование:

 catch(Exception ex)
{
    _log.TraceException(ex);
}