【问题标题】:Multicast OnExceptionAspect is logging bubbling exceptionsMulticast OnExceptionAspect 正在记录冒泡异常
【发布时间】:2012-04-25 10:50:38
【问题描述】:

我有一个来自Postsharpmulticast OnExceptionAspect,它应用于装配级别。这自然意味着所有方法在抛出异常时都会调用 Aspect。

在 Aspect 中,我正在记录异常详细信息包括参数值,当异常发生时,这是正常工作的。

但是,由于这适用于程序集中的所有方法,因此会为堆栈中的每个方法创建一个日志条目,因为每个方法都会出现异常。

我对如何防止这种情况一无所知,最初我打算比较异常(看看它是否相同),但这似乎很混乱。以前一定有人遇到过这个问题,有什么想法吗?

【问题讨论】:

  • 预期的行为是什么?你不清楚这一点。
  • 道歉。我希望能够在异常发生时记录方法的堆栈跟踪和参数。但我也希望它像往常一样向上传播堆栈(无需随后再次记录异常)。

标签: c# exception exception-handling log4net postsharp


【解决方案1】:

这个问题有两种解决方案。

A.使用线程静态字段来存储已记录的任何异常。

[Serializable] 
public class MyAspect : OnExceptionAspect 
{ 
    [ThreadStatic]
    private static Exception lastException;

    public override void OnException(MethodExecutionArgs args) 
    { 
      if(args.Exception != lastException) 
      { 
        string msg = string.Format("{0} had an error @ {1}: {2}\n{3}",  
            args.Method.Name, DateTime.Now,  
            args.Exception.Message, args.Exception.StackTrace); 

        Trace.WriteLine(msg); 
        lastException = args.Exception;
      } 

    }  
}

B.向 Exception 对象添加标签。

[Serializable] 
public class MyAspect : OnExceptionAspect 
{ 
    private static object marker = new object();

    public override void OnException(MethodExecutionArgs args) 
    { 
      if(!args.Exception.Data.Contains(marker)) 
      { 
        string msg = string.Format("{0} had an error @ {1}: {2}\n{3}",  
            args.Method.Name, DateTime.Now,  
            args.Exception.Message, args.Exception.StackTrace); 

        Trace.WriteLine(msg); 
        args.Exception.Data.Add(marker, marker);
      } 

    }  
}

【讨论】:

    【解决方案2】:

    仅供参考--Gael 是 PostSharp 专家,因为他受雇于那里……所以您知道。

    您总是可以通过检查 StackTrace 来判断异常源自何处。 StackTrace 通过 args.Exception.StackTrace 提供。你可以试试 Dustin Davis(另一个 PostSharp 员工)在这里推荐的东西:PostSharp - OnExceptionAspect - Get line number of exception

    解析 StackTrace(通过此处概述的方法:How to split a stacktrace line into namespace, class, method file and line number?)然后将 args.Method.Name 与解析结果进行比较。如果您的 args.Method.Name 与原始方法相同(通过解析 StackTrace 找到),那么您知道应该记录它,否则忽略。

    这里有一些代码可以让我的解决方案更加具体(基于前面提到的两个解决方案):

    [Serializable]
    public class ExceptionWrapper : OnExceptionAspect
    {
        public override void OnException(MethodExecutionArgs args)
        {
            var st = new StackTrace(args.Exception, true);
            var frame = st.GetFrame(0);
            var lineNumber = frame.GetFileLineNumber();
            var methodName = frame.GetMethod().Name;
            if(methodName.Equals(args.Method.Name))
            {
                string msg = string.Format("{0} had an error @ {1}: {2}\n{3}", 
                    args.Method.Name, DateTime.Now, 
                    args.Exception.Message, args.Exception.StackTrace);
    
                Trace.WriteLine(msg);
            }
        } 
    }
    

    (或者,老实说,您可以使用 Gael 推荐的解决方案之一。)

    【讨论】:

      【解决方案3】:

      我可以看到这样做的一种方法是定义一个自定义异常并在您的方面抛出该异常。然后在您的方面也在登录之前检查异常,如果它不是您的自定义异常记录它,否则不要记录它并(重新抛出?)。

      这就是示例代码的样子:

      [Serializable]
      public class DatabaseExceptionWrapper : OnExceptionAspect
      {
          public override void OnException(MethodExecutionArgs args)
          {
            if(!(args.Exception is CustomException))
            {
              string msg = string.Format("{0} had an error @ {1}: {2}\n{3}", 
                  args.Method.Name, DateTime.Now, 
                  args.Exception.Message, args.Exception.StackTrace);
      
              Trace.WriteLine(msg);
            }
      
            throw new CustomException("There was a problem");
          } 
      }
      

      当然,您仍然必须定义该异常和所有内容。 :)

      【讨论】:

      • 好主意,但是我如何判断异常是源自该方法还是从下面冒泡?
      • @m.edmondson:有关系吗?您知道自定义异常是由方面抛出的,并且您已经记录了它,不管它被抛出多深,不是吗?
      • 我想不是,但我只是不想在我的日志中填满无用的信息——只是阻碍。
      • @m.edmondson:你不会因为你知道不记录在你的方面引发的异常。这也是我的示例所做的。
      猜你喜欢
      • 1970-01-01
      • 2011-05-13
      • 2015-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多