C#SmtpClient.Send() - 处理异常的任何替代(或伴随)?

时间:2009-07-10 02:26:43

标签: c# exception

(SO的长期读者,第一次问q。

我很擅长C#多年来一直在PHP / Ruby / Python世界中,所以如果这是一个愚蠢的问题,我很抱歉。)

我正在对旧的C#应用​​程序进行一些维护,每当SmtpClient.Send()失败时崩溃。从我从MSDN中收集的那些小东西中,我可以看到解决这个问题的明显方法,但我的问题还是关注更一般的情况。

根据MSDN:

  try {
          client.Send(message);
  }  
  catch (Exception ex) {
          Console.WriteLine("Exception caught in CreateTestMessage2(): {0}", 
                ex.ToString() );
  }

这一切都对我有意义,但我也一直认为,只要你能够防止出现错误的可能性,你就会这样做。你能做什么(而且应该?)来减少Send()抛出异常的可能性吗?

我假设有些情况下不可能阻止异常的可能性,所以你必须处理它,但是有没有人们用它来指导它们的一般风格指南或规则?

再次,对不起,如果这是一个垃圾问题。我尽可能多地尝试搜索SO和Google。

编辑:我刚发现这个问题Best practices for exception management in java or C  这可能会回答我的问题。

EDIT2:感谢您的快速反馈,非常快。我一直在考虑这个问题,也许这可以进一步完善我的要求。

说某些异常,如SmtpException,真的无法避免,这是正确的吗?是否更正确的说法是使用像SmtpException这样的异常来告诉你发送出错的地方是正确的风格而你只是按照自己喜欢的方式处理它?<​​/ p>

我觉得这个问题听起来有些黯淡,但我问,因为我能学到的任何东西都有利于我的信心。

5 个答案:

答案 0 :(得分:4)

这是我称之为“外生”异常情况的一个很好的例子。

http://ericlippert.com/2008/09/10/vexing-exceptions/

考虑一个类似的案例 - 打开一个文件。您可以通过以下方式减少获得异常的机会:

  • 检查文件是否存在
  • 检查用户是否有权打开文件
  • 检查另一个应用程序是否已锁定文件
  • 嗒嗒
  • blah blah
  • blah blah blah

您可以执行所有操作,并在打开文件时仍然获得异常。因为在执行所有这些检查并尝试打开文件之间,某些内容可能已更改。另一个进程可能已更改权限,或锁定文件,或用户从驱动器中删除了CD-ROM,或其他任何操作。行动是否成功是基于一种外生的,现实世界的条件,你不能以任何保证的方式进行测试。

外生异常是一种难以处理的问题,因为即使你做了很多工作来消除它们,你也必须处理它们。

发送邮件的方式是一样的。您可以检查各种事情以尝试消除异常,这可能会在99%的时间内起作用,但您仍然无法保证在您的所有检查和实际发送邮件之间,有人没有拔掉路由器在错误的时刻。你只需要搞砸它并处理异常。

答案 1 :(得分:3)

捕获异常时,如果您知道调用方法会遇到什么类型的异常,请尽可能具体。例如,这将允许诸如OutOfMemoryException之类的错误继续冒泡堆栈,它应该处于未处理状态,然后您的应用程序将快速失败(这可能是一件好事,因为您的系统现在处于未知状态而您不应该继续)。

然而,有不同的思想流派;在某些情况下(比如你是一个NT服务)你想要你的应用程序的高可用性,并且因为你在一些无法预料的代码路径上得到NullPointerException而在生产中崩溃可能是不可取的,只要该异常被记录并且你有能力然后发出QFE(更不用说修改你的测试制度)。如果你是一个控制台或表单应用程序,那么恢复是一个不同的故事,因为异常可能浮现在用户面前,他们可以交互式地决定适当的操作是什么。

我的一般建议:捕获尽可能接近源的特定异常,让其余的事件冒出堆栈并将其记录在您有足够上下文的位置,以便稍后尝试并重新生成异常。警惕抓住然后重新投掷是昂贵的;在你的例子中你可能想要这样做的一个场景是,如果,例如,SmtpException是一个连接超时(我正在做这个),那么一个策略可能是指数退避并且自邮件以来重试n次如果你没有成功,服务器可能会关闭,然后最终放弃并重新抛出。

真正简短的回答是:一切都取决于。

答案 2 :(得分:1)

通过阅读MSDN,您可以看到.Send()方法抛出的异常列表以及抛出它们的简要原因。在调用Send()之前检查这些并处理它们可以帮助避免它们 - 但是文档不一定涵盖所有可能的异常或原因。

你走在正确的道路上;如果可能的话,你想要避免创建例外是对的。如果没有其他原因,运行时创建和处理它们相当昂贵 - 如果它们未处理,即使是简单的异常也会导致整个应用程序崩溃。

答案 3 :(得分:1)

本身的例外并不是很糟糕。他们是防御性编程策略的一部分。您将从发现崩溃原因的异常中获得宝贵的知识。您可以使用它来解决问题。

答案 4 :(得分:0)

当发生异常错误时抛出异常是完全可以的,所以你的代码没有任何问题。如果SMTP服务器关闭或电子邮件地址无效或出现其他一些错误,您想要它会抛出而不是静默失败。

您是否想要立即围绕发送的尝试块取决于您是否有任何事情要做。否则,你可能会让它冒泡到最大的尝试块。