简体   繁体   English

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

[英]C# SmtpClient.Send() - Any alternative (or companion) to handling the exception?

(Long time reader of SO, first time asking a q. (SO的长期读者,第一次问q。

I'm quite new to C# having been in the PHP/Ruby/Python world for many years so I apologise if this is a dopey question.) 我很擅长C#多年来一直在PHP / Ruby / Python世界中,所以如果这是一个愚蠢的问题,我很抱歉。)

I'm doing some maintenance on an old C# app that is crashing whenever SmtpClient.Send() fails. 我正在对一个旧的C#应用​​程序进行一些维护,每当SmtpClient.Send()失败时崩溃。 From the little I've gleaned from the MSDN, I can see the obvious way to fix this, but my question is also concerned with the more general case. 从我从MSDN收集的那些小东西中,我可以看到解决这个问题的明显方法,但我的问题还是关注更一般的情况。

As per the MSDN: 根据MSDN:

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

This all makes sense to me, but I've also always thought that whenever you can prevent the possibility of the error you do so. 这一切都对我有意义,但我也一直认为,只要你能防止错误的可能性,你就会这样做。 Is there anything you can (and should?) do here to reduce the possibility of the Send() throwing exceptions? 有没有什么可以(而且应该?)在这里做什么来减少Send()抛出异常的可能性?

I'm assuming there are situations where it's impossible to prevent the possibility of an exception, so you have to handle it, but are there any general style guide or rules that people use to guide them? 我假设有些情况下不可能阻止异常的可能性,所以你必须处理它,但是有没有人们用来指导它们的一般风格指南或规则?

Again, sorry if this is a crap question. 再次,对不起,如果这是一个垃圾问题。 I tried searching SO and Google as much as I could. 我尽可能多地尝试搜索SO和Google。

EDIT: I just found this question Best practices for exception management in java or C which may well go someway to answering my question. 编辑:我刚刚发现这个问题java或C中的异常管理的最佳实践 ,可能会回答我的问题。

EDIT2: Thanks for the prompt feedback, incredibly fast. EDIT2:感谢您的快速反馈,非常快。 I've been thinking about the problem a bit more and perhaps this could further refine what I'm asking. 我一直在考虑这个问题,也许这可以进一步完善我的要求。

Is it correct to say that certain exceptions, like SmtpException, really can't be avoided? 说某些异常,如SmtpException,真的无法避免,这是正确的吗? Is it even more correct to say that it is the correct style to use exceptions like SmtpException to tell you that something went wrong with the send and you just handle it however you'd like? 是否更正确的说法是使用像SmtpException这样的异常来告诉你发送出现问题的正确方式而你只是处理它而不是你想要的?

I feel like I'm sounding a bit dim in this question, but I'm asking because anything I can learn is good for my confidence. 我觉得我在这个问题上听起来有些暗淡,但我问,因为我能学到的任何东西都有利于我的自信。

This is a good example of what I call an "exogenous" exception situation. 这是我称之为“外生”异常情况的一个很好的例子。

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

Consider an analogous case -- opening a file. 考虑类似的情况 - 打开文件。 You can reduce the chance of getting an exception by: 您可以通过以下方式减少获得异常的机会:

  • checking whether the file exists 检查文件是否存在
  • checking whether the user has permission to open the file 检查用户是否有权打开文件
  • checking whether another application has locked the file 检查另一个应用程序是否已锁定该文件
  • blah 胡说
  • blah blah 等等等等
  • blah blah blah 等等等等等等

You can do all that and STILL get an exception when you open the file. 您可以执行所有操作,并在打开文件时仍然获得异常。 Because between doing all those checks and you trying to open the file, something might have changed. 因为在执行所有这些检查并尝试打开文件之间,某些内容可能已更改。 Another process might have changed the permissions, or locked the file, or the user removed the CD-ROM from the drive, or whatever. 另一个进程可能已更改权限,或锁定文件,或用户从驱动器中删除了CD-ROM,或其他任何操作。 Whether the action succeeds or not is based on an exogenous, real-world condition that you cannot test for in any kind of guaranteed way. 行动是否成功是基于一种外生的,现实世界的条件,你无法以任何保证的方式进行测试。

Exogenous exceptions are a pain to deal with, because you HAVE to handle them even if you do lots of work to eliminate them. 外部异常是一种难以处理的问题,因为即使你做了很多工作来消除它们,你也必须处理它们。

Sending mail is the same way. 发送邮件的方式是一样的。 You can check all kinds of things to try to eliminate the exception, which probably will work 99% of the time, but you still cannot GUARANTEE that between all your checks and the actual attempt to send mail, that someone didn't unplug the router at exactly the wrong moment. 您可以检查各种事情以尝试消除异常,这可能会在99%的时间内起作用,但您仍然无法保证在您的所有检查和实际发送邮件之间,有人没有拔掉路由器在错误的时刻。 You're just going to have to suck it up and handle the exceptions. 你只需要搞砸它并处理异常。

When catching exceptions, be as specific as possible if you know what kinds of exceptions to expect from the invoked method. 捕获异常时,如果您知道调用方法会遇到什么类型的异常,请尽可能具体。 This will allow, for example, errors such as OutOfMemoryException to continue to bubble up the stack where it should go unhandled and then your app will fail fast (which is probably a good thing because your system is now in an unknown state and you should not carry on). 例如,这将允许诸如OutOfMemoryException之类的错误继续冒泡堆栈,它应该处于未处理状态,然后您的应用程序将快速失败(这可能是一件好事,因为您的系统现在处于未知状态而您不应该继续)。

There are different schools of thought on this, however; 然而,对此有不同的思想流派; in some instances (say you're an NT service) you want high availability of your app, and crashing in production because you get NullPointerException on some unforeseen code path may not be desirable as long as that exception gets logged and you have the ability to then issue a QFE (not to mention revise your test regime). 在某些情况下(比如你是一个NT服务)你想要你的应用程序的高可用性,并且因为你在一些无法预料的代码路径上得到NullPointerException而在生产中崩溃可能是不可取的,只要该异常被记录并且你有能力然后发出QFE(更不用说修改你的测试制度)。 If you're a console or forms app, then recovery is a different story since the exception could be surfaced to the user and they can interactively decide what the appropriate action is. 如果您是一个控制台或表单应用程序,那么恢复是一个不同的故事,因为异常可能浮现在用户身上,他们可以交互式地决定适当的操作是什么。

My general advice: catch specific exceptions as close to the source as possible, let the rest bubble up the stack and have it logged at a point where you have enough context to later on try and repro the exception. 我的一般建议:捕获尽可能接近源的特定异常,让其余的在堆栈中冒泡并将其记录在您有足够上下文的位置,以便稍后尝试并重新生成异常。 Be wary that catching then re-throwing is expensive; 警惕抓住然后重新投掷是昂贵的; a scenario in your example where you might want to do this would be if, say, the SmtpException was a connection timeout (I'm making this up), then one strategy might be exponential back off and retry up to n times since the mail server might be down, then finally give up and rethrow if you don't succeed. 在你的例子中你可能想要这样做的一个场景是,如果,例如,SmtpException是一个连接超时(我正在做这个),那么一个策略可能是指数退避并且自邮件以来重试n次如果你没有成功,服务器可能会关闭,然后最终放弃并重新抛出。

The really short answer is: It All Depends. 真正简短的回答是:一切都取决于。

By reading MSDN you can see the list of Exceptions thrown by the .Send() method and abbreviated reasons why they would be thrown. 通过阅读MSDN,您可以看到.Send()方法抛出的异常列表以及抛出它们的简要原因。 Checking for these and handling them prior to calling Send() can help avoid them--but the documentation doesn't necessarily cover all possible exceptions or reasons why they could occur. 在调用Send()之前检查这些并处理它们可以帮助避免它们 - 但是文档不一定涵盖所有可能的异常或它们可能发生的原因。

You're on the right path though; 你在正确的道路上; and you're right that you want to avoid creating exceptions if possible. 如果可能的话,你想要避免创建例外是对的。 If for no other reason they are fairly expensive for the runtime to create and handle--and if they go unhandled even a simple exception can cause the whole app to crash. 如果没有其他原因,它们对于运行时创建和处理来说相当昂贵 - 如果它们未处理,即使是简单的异常也会导致整个应用程序崩溃。

The exceptions are not very bad per se. 例外情况本身并不是很糟糕。 They are part of defensive programming strategy. 他们是防御性编程策略的一部分。 You will get valuable knowledge from exception caught regarding the causes of crashing of Send. 您将从发现崩溃原因的异常中获得宝贵的知识。 Which you will be able to use to fix the problems. 你将能够用来解决问题。

It's completely ok to throw an exception when an exceptional error occurs, so there's nothing wrong with your code. 发生异常错误时抛出异常是完全可以的,因此代码没有任何问题。 If the SMTP server is down or the email address is invalid or some other mistake is made, you want it to throw rather than fail silently. 如果SMTP服务器关闭或电子邮件地址无效或出现其他错误,您希望它以静默方式抛出而不是失败。

Whether you want a try block immediately surrounding the Send depends on whether there's anything for you to do here. 您是否想要立即围绕发送的尝试块取决于您是否有任何事情要做。 Otherwise, you might as well let it bubble up to the to-most try block. 否则,你可能会让它冒泡到最大的尝试块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM