多播OnExceptionAspect正在记录冒泡异常

问题描述 投票:2回答:3

我有来自multicastOnExceptionAspect Postsharp,它适用于装配级别。这自然意味着所有方法在抛出异常时都会调用Aspect。

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

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

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

c# exception exception-handling log4net postsharp
3个回答
4
投票

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

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

    }  
}

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推荐的解决方案之一。)


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

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

© www.soinside.com 2019 - 2024. All rights reserved.