我有来自multicast的OnExceptionAspect Postsharp,它在程序集层面上应用。这自然意味着所有方法在抛出异常时都会调用Aspect。
在Aspect中我记录了异常详细信息,包括发生异常时传递的参数值,这是正常的。
但是,因为这适用于程序集中的所有方法,所以会为堆栈中的每个方法创建一个日志条目,因为异常会在每个方法中冒泡。
我没有关于如何防止这种情况的想法,最初我要比较异常(看它是否是同一个),但这看起来很混乱。以前有人必须遇到过这个问题吗?
答案 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");
}
}
当然,您仍然需要定义该异常和所有内容。 :)