C#(不是ASP / MVC / WinForms) - 捕获类中的所有异常

时间:2011-07-07 13:18:19

标签: c# .net exception exception-handling

一些背景信息

我在一个使用专有编程语言的系统中编程,可以选择在专有代码中使用特别归属的.Net类。

不幸的是,系统无法处理从.Net代码冒出来的未处理异常,如果事实上根本没有;系统崩溃,没有任何解释。这很烦人,因为我们经常希望处理专有系统中的异常,而不是.Net代码。系统供应商提供的解决方案是将异常重新打包到系统 处理的特殊对象中。

我们的.Net代码是以外观模式编写的,问题是为了确保处理从.Net代码冒出的每个异常,外观中的每个方法都必须包含一个重新打包的try / catch块。可能发生的异常。

问题

我在这里阅读了许多描述类似场景的线程,其中大多数是WinForms-或与Web相关。因为我们的代码都不是,所以问题是是否有某种方法来捕获类中的所有异常,以便我们可以重新打包它并重新抛出它们的修改版本?

显然,包含类和专有语言的.Net dll之间的接口完全超出了我们的控制范围。

修改

我尝试了@VMAtm建议的currentDomain.UnhandledException方法,遗憾的是无济于事。事件处理程序没有触发,父系统得到了异常,然后像往常一样行为不端。这导致我再次进入谷歌,我发现这段here

  

首先要理解的是UnhandledException事件不是未处理的异常“处理程序”。注册事件,与文档说的相反:-(,不会导致未处理的异常被处理。(从那以后它们不会被处理,但我将停止循环推理已经......)UnhandledException事件只是通知您异常未处理,以防您想在线程或应用程序死亡之前尝试保存状态。

     

Jonathan Keljo,CLR Exceptions PM

这太糟糕了,我喜欢有一个“全局”try / catch块的想法。我猜这意味着我没有成功地从父系统中隐藏异常。因为我不知道关于如何在该系统中实现这一点的第一件事(坦率地说,我不知道我将如何继续自己实现它的第一件事)我和我的关系非常薄假设,所以如果有人能以任何方式纠正我,请继续!

哦,我在父系统中得到的错误是Exception has been thrown by the target of an invocation.,据我所知,这是来自外部.Net异常的消息。如果可以从中读出任何内容,我不知道。

我也会去@jlew建议的Castle Dynamic Proxy,但它看起来比两条AppDomain线要困难得多,并且让我感到非常害怕:)

解决方案

如果你遇到与我相同的问题,你应该首先尝试@VMAtm建议的currentDomain.UnhandledException方法,因为这是因为我的父系统特别肛门它不起作用。

我使用Castle DynamicProxy设置让它工作。这真的很容易设置。我的测试用例是封装XmlAttribute类的façade类。我要做的第一件事就是编写代理类:

public class AttribInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        try
        {
            invocation.Proceed();
        }
        catch (Exception e)
        {
            // Custom exception repackaging here
        }
    }
}

然后我必须指示façade对象实际使用代理。我保留了我的旧后端字段,但在c'tor中添加了以下内容:

public class CapXmlAttribute : CapPmlNetObject
{
    private XmlAttributeBackend _xmlAttribute;

    public CapXmlAttribute()
    {
        var generator = new ProxyGenerator();
        _xmlAttribute = (XmlAttributeBackend) generator.CreateClassProxy(
            typeof (XmlAttributeBackend), new AttribInterceptor());
    }
}

最后一步是将后端中暴露于外观的所有方法设置为virtual。对我来说这不是问题,但对其他人来说可能是一个破坏者。

DynamicProxy确实没有那么好记录,但我从Krzysztof Koźmic's tutorialHamilton Verissimo's codeproject学到了很多东西。

3 个答案:

答案 0 :(得分:11)

当我理解答案时,你需要抓住并重新抛出未处理的异常,对吧? 您可以为AppDomain.UnhandledException Event添加处理程序:

  AppDomain currentDomain = AppDomain.CurrentDomain;
  currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);

  static void MyHandler(object sender, UnhandledExceptionEventArgs args)
  {
        Exception e = (Exception) args.ExceptionObject;
        // handle exception here, you can easily package exceptions there.
  }

更新

我在AppDomainAppDomain.FirstChanceException Event中发现了另一个事件:

  

在运行时在应用程序域中搜索调用堆栈中的异常处理程序之前,在托管代码中抛出异常时发生。

可能这可以解决您的问题 - 此事件发生在之前 catch块中的任何代码。

答案 1 :(得分:4)

我会看一下像Castle Dynamic Proxy这样的东西 这将允许以通用方式拦截您的类方法调用,这将为您提供放置“catch-all”异常处理程序的中心位置。 (那就是说,我不清楚你的类实际上是如何实例化的,这可能会使这种方法成为问题)

答案 2 :(得分:2)

除了VMAtm的帖子,您还可以为ThreadExceptions设置事件处理程序