在.Net中,是否可以在类中的任何方法传递到调用堆栈之前捕获所有未处理的异常
本文关键字:堆栈 异常 未处理 调用 是否 Net 方法 任何 | 更新日期: 2023-09-27 18:11:50
问题:
我想从类中的任何方法捕获任何异常,这样我就可以在异常传递到堆栈之前将类特定的数据记录到异常中进行日志记录。我知道我可以在类的每个方法中都放一个try-catch,但有很多方法,似乎应该有一个更有效的方法。
我目前正在做的事情示例:
public class ClassA
{
private int x;
private int y;
public void Method1()
{
try
{
//Some code
}
catch(Exception ex)
{
ex.Data.Add("x", x);
ex.Data.Add("y", y);
throw;
}
}
public void Method2()
{
try
{
//Some code
}
catch (Exception ex)
{
ex.Data.Add("x", x);
ex.Data.Add("y", y);
throw;
}
}
}
我想做的示例:
public class ClassB : IUnhandledErrorHandler
{
private int x;
private int y;
public void Method1()
{
//Some code
}
public void Method2()
{
//Some code
}
void IUnhandledErrorHandler.OnError(Exception ex)
{
ex.Data.Add("x", x);
ex.Data.Add("y", y);
throw;
}
}
public interface IUnhandledErrorHandler
{
void OnError(Exception ex);
}
注意:此类是WCF项目中的服务,并实现ServiceContract。我已尝试将ErrorHandler添加到服务的ChannelDispatcher中。但是,当错误到达ErrorHandler时,它已经超出了发生错误的类的范围,因此我无法访问类的详细信息。
解决方案:
public class ClassC
{
public ClassC()
{
AppDomain.CurrentDomain.FirstChanceException += OnError;
}
private int x;
private int y;
public void Method1()
{
//Some code
}
public void Method2()
{
//Some code
}
private void OnError(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)
{
e.Exception.Data["x"] = x;
e.Exception.Data["y"] = y;
}
}
如果在.NET 4上运行,则可能会使用AppDomain中的FirstChanceException事件。
您可以通过从System.ContextBoundObject继承来实现这一点。它并不像您希望的那样漂亮,我相信可能会有一些显著的开销,但据我所知,这是实现您所描述的功能的唯一方法。
根据要求,这里有进一步的阐述。。。如前所述,它并不漂亮,但这里有一个使其工作所需的最低限度的实现。感兴趣的主要方法是AOPSink.SyncProcessMessage方法。它是在"Test"对象上的任何方法之前调用的,对NextSsink.SyncProcessMessage(msg(的调用实际上是调用最初调用的方法。您可以通过播放传递给SyncProcessMessage的IMessage参数来检查(和修改(调用了哪个方法和传递的参数,还可以通过播放从NextSink.SyncProcessMessage返回的IMessage来检查/修改返回值(或抛出的Exception(。此功能存在显着的性能开销,因此,除了调试目的之外,我不建议将其用于高流量对象。
[AOP]
class Test : ContextBoundObject
{
public void TestMethod()
{
throw new Exception();
}
}
[AttributeUsage(AttributeTargets.Class)]
public class AOPAttribute : ContextAttribute
{
public AOPAttribute() : base("AOPAttribute") { }
public override void GetPropertiesForNewContext(IConstructionCallMessage ctor)
{
ctor.ContextProperties.Add(new AOPProperty());
}
public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
{
return false;
}
}
public class AOPProperty : IContextProperty, IContributeServerContextSink
{
public IMessageSink GetServerContextSink(IMessageSink nextSink)
{
return new AOPSink(nextSink);
}
public string Name { get { return "AOP"; } }
public bool IsNewContextOK(Context ctx) { return true; }
public void Freeze(Context ctx) { }
}
public class AOPSink : IMessageSink
{
public AOPSink(IMessageSink nextSink) { this.NextSink = nextSink; }
public IMessageSink NextSink { get; private set; }
public IMessage SyncProcessMessage(IMessage msg)
{
// inspect method+params by playing with 'msg' here
IMessage m = NextSink.SyncProcessMessage(msg);
// inspect returnval/exception by playing with 'm' here
return m;
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
throw new NotSupportedException();
}
}