【问题标题】:Unhandled Exceptions in C# Class Library for Logging Purposes用于记录目的的 C# 类库中未处理的异常
【发布时间】:2011-07-27 19:29:01
【问题描述】:

我是软件开发的新手,也是 stackoverflow 的新手,所以请放轻松。

背景:我正在开发一个 C# 类库,用于处理第三方应用程序通过 tcp/ip(使用异步套接字)发送的 xml 消息。我正在使用 com-interop 将类库公开给 Vb6 应用程序。当 C# 库处理它通过套接字接收的 xml 时,它会引发消费 vb6 应用程序订阅的各种事件(这样,当我们最终在 .Net 中重写整个应用程序时,我们已经完成了这个组件)。

问题:我想捕获所有未处理的异常,仅用于记录目的。在 winforms 应用程序中,您可以将事件连接到 AppDomain.CurrentDomain.UnhandledException 和 Application.ThreadException。有没有办法类似地抓取异常数据来记录类库中的信息?

要点:

  • 我不是试图从这些异常中恢复,只是记录它们并让异常传播并在需要时使应用程序崩溃。

  • 我正在尽最大努力在本地捕获所有我知道可能发生的特定异常。因此,我的目的是只记录真正意外的异常。

  • 我知道有些人会说这将是一个糟糕的设计模式。我应该让调用者处理这些异常。问题是 vb6 应用程序没有像我想要的那样强大的错误处理。首先,我想记录堆栈跟踪,以便如果 vb6 应用程序由于我的 dll 而崩溃,我可以查看日志,以便提醒我的 c# 代码中可能需要更改的潜在区域。

谁能给我一些指导?到目前为止,我发现的最佳选择似乎是在每个公共方法中放置一个通用的 try catch 块,记录异常,然后抛出它。这似乎不太理想:

public void SomeMethod()
{
    try
    {
        // try something here...
    }
    catch (Exception ex)
    {
        Log(ex);
        throw;
    }
}

这不仅看起来像一个糟糕的设计,而且我不知道如果其中一个异步回调在与调用该方法的线程不同的线程上导致异常会发生什么。这个通用的 try/catch 块还会捕获这样的异常吗?

感谢您的帮助。

编辑:我最初将@Eric J. 的答案标记为正确,但在尝试实施该解决方案后,我发现它不适用于来自套接字类的异步回调我正在使用。一旦使用线程池线程触发异步回调,我似乎无法捕获堆栈中稍后发生的任何异常。我需要使用 AOP 框架,还是有其他方法可以捕获这些异常?

【问题讨论】:

  • 这里真正的问题是我的异步回调函数中没有顶级 catch 块。由于它们在单独的线程(线程池线程)上运行,因此它们的异常不会“冒泡”备份到其他任何地方。对于这种情况,AOP 似乎是一个很好的解决方案,可以避免如此多的顶级 catch 块。这是我打算在更远的地方投入一点时间的事情。
  • 为什么 AppDomain.CurrentDomain.UnhandledException 不适用于类库?

标签: c# multithreading com-interop class-library unhandled-exception


【解决方案1】:

如果您的库入口点有限,请考虑按照您的建议进行操作 - 使用 .NET 包装器类或包装器库来执行实际的互操作并在该包装器类中捕获/记录异常。返回调用 VB6 库知道如何处理的异常或错误代码(是否重新抛出异常取决于 VB6 代码可以处理的内容)。

CrazyDart 建议使用 IOC,这是一个有趣且有效的替代方案,但最初也会增加复杂性和学习曲线。当然也可以看看 IOC 并认为它是一种可能性。

【讨论】:

  • 从范式的角度来看,这似乎不是理想的解决方案,但同样,考虑到我的时间限制,这似乎是当前项目的最佳选择。感谢您的输入。只是为了澄清一下,您是建议多一层包装,还是仅仅需要做 com 互操作?
  • 不,只是一个执行 COM 互操作并处理异常的层。如果您有大量方法要包装,您会考虑编写一个小的代码生成器,例如获取 COM 中每个类的方法列表并输出适当的 C# 代码。我之前在包装一个非常大的 COM 业务层时这样做了。再说一次,如果它真的很大,那么在 IOC 上投入时间可能是值得的。
  • 谢谢。标记为答案,因为这个解决方案目前最适合我。
  • 不幸的是,我试图实现这一点,但我遇到了调用异步回调后抛出异常的问题。请参阅我上面的编辑。请告知您是否可以想办法捕获这些异常。
  • 好吧,由于没有其他回应...我将其标记为最终答案。但是,我要指出,在这种情况下,我需要做的主要事情是确保在每个线程的开头使用顶级 catch 语句,包括异步回调函数。
【解决方案2】:

您可以为此使用温莎城堡和拦截器。这是在项目中使用 IOC 的一个很好的理由。

http://blog.andreloker.de/post/2009/02/20/Simple-AOP-integrating-interceptors-into-Windsor.aspx

正如您所说,我已将它们用于异常日志记录,以及性能日志记录...除此之外,您还可以将拦截器用于类似事务。

【讨论】:

  • 我在项目中使用过 IOC,我个人认为它为大型项目增加了最大的好处,其中有几个团队负责不同的领域(不同的关注点)。我知道这是踏入圣战领域,只是分享我的个人经历。
  • 一切都有它的位置......问题是关于高级主题恕我直言,需要一种相当高级的方法才能正确解决。我同意其他一些帖子,即 AOP(与拦截器几乎相同)是一种有效的方法。从哲学上讲,有些人选择永远不种果树。我经常种很多。后来我收获很大。很多人问我怎么会有这么多好看的果树,我告诉他们我经常种植。有些人死了,许多人没有。因为学习很难而忽视学习,这使得某人适合服务和劳动工作而不是工程。
  • 感谢 CrazyDart。我同意这个问题似乎相当高级,可能需要一种高级方法。不幸的是,所有这些对我来说都是新的(我只开发了大约 6 个月,仅在过去 2 个月全职)。我已经为未来的 AOP 框架和 Castle Windsor 添加了书签。鉴于我对当前项目的时间限制,我倾向于 Eric 的方法。如果您在上述情况下对此有任何具体见解或疑虑,请随时提出建议。再次感谢。
  • 了解您的经验水平,我想说不要试图咬掉 IOC。它相当先进,您最终会遇到很多麻烦。在国际奥委会等几年。
  • @CrazyDart:我同意...持续学习是掌握艺术和专业的关键。
【解决方案3】:

您可以考虑使用 Spring.NET 或 Unity 之类的 AOP 框架,或者查看 PostSharp 之类的产品(尽管我从未亲自尝试过 PostSharp)。

【讨论】:

  • 感谢您的信息。我会将这些框架添加到书签中,并在将来再次使用它们。目前,鉴于我对项目的时间限制,我担心学习曲线可能太长而无法实施。
猜你喜欢
  • 2018-11-02
  • 2015-10-21
  • 1970-01-01
  • 2020-09-01
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多