多播OnExceptionAspect正在记录冒泡异常

时间:2012-04-25 10:50:39

标签: c# exception exception-handling log4net postsharp

我有来自multicastOnExceptionAspect Postsharp,它在程序集层面上应用。这自然意味着所有方法在抛出异常时都会调用Aspect。

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

但是,因为这适用于程序集中的所有方法,所以会为堆栈中的每个方法创建一个日志条目,因为异常会在每个方法中冒泡。

我没有关于如何防止这种情况的想法,最初我要比较异常(看它是否是同一个),但这看起来很混乱。以前有人必须遇到过这个问题吗?

3 个答案:

答案 0 :(得分:4)

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

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

[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);
      } 

    }  
}

答案 1 :(得分:3)

仅供参考 - 盖尔是一位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推荐的解决方案之一。)

答案 2 :(得分:0)

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

这就是示例代码的样子:

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

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