我正在与同事讨论何时抛出错误以及何时不在WCF服务中抛出错误。
有一种观点认为,当服务操作由于某些错误而无法完成工作时,我们只会抛出错误;由于它,某些东西可能处于无效状态。所以,举一些例子:
ValidateMember(字符串名称,字符串密码,字符串国家/地区) - >如果未传递强制参数,则会抛出错误,因为验证本身无法执行; - >如果发生了一些内部错误,就像数据库已关闭一样会抛出错误 - >将在所有其他情况下返回状态合同,指定验证结果(MemberValidated,WrongPassword,MemberNotKnown,...)
GetMember(int memberId) - >只有在某些事情发生故障时才会抛出错误,在所有其他情况下它会返回成员,如果没有找到则返回null
另一种意见是,当GetMember找不到该成员时,我们也应该抛出错误,或者在ValidateMember的情况下,密码错误。
你怎么看?答案 0 :(得分:12)
我对此的看法......
失败有三个原因:
由您决定如何将实际故障合同映射到每个故障原因。例如,我们这样做:
我们借用原因3的Microsoft EntLib class,并使用exception shielding以声明方式处理原因1和2。它使代码非常简单。
澄清:
我们在服务中处理这样的三个原因:
FaultException<ServiceFault>
抛给仅包含错误ID的客户端。ArgumentException
,但任何合适的类型都可以。一旦抛出它,它的处理方式与(1)完全相同,因为我们希望它与客户端看起来相同。FaultException<ValidationFault>
。我们将异常屏蔽配置为通过un-wrapped传递此异常屏蔽,因此它在客户端上显示为FaultException<ValidationFault>
而不是FaultException<ServiceFault>
。最终结果:
FaultException<ValidationFault>
。所有其他异常类型(包括FaultException<ServiceFault>
)都由客户端的全局错误处理程序处理为致命错误,因为服务中的致命错误通常也意味着客户端中的致命错误。答案 1 :(得分:3)
这是一种常见的常规故障,然后抛出故障是一个错误。应该编写软件来处理例行项目,例如输入错误的密码。故障处理是出现异常故障,不属于程序正常设计的一部分。
例如,如果您的程序编写时认为它始终可以访问数据库,并且数据库无法访问,那么“修复”远远超出了软件的限制。应该抛出一个错误。
故障处理在编程语言的结构中使用不同的逻辑流程,只有当你“离开”编程问题的正常处理时才使用它,你将使你的解决方案利用编程语言的特性。一种看起来更自然的方式。
答案 2 :(得分:2)
我认为将错误处理和错误处理分开是一种好习惯。任何错误情况都应由您的程序处理 - 故障处理保留用于特殊情况。作为两者分离的指南,我发现在考虑这些情况时要记住只有三种类型的错误(处理数据和消息时)和只有一种类型的错误时,它很有用。 错误类型与不同类型的验证有关:
消息验证 - 您可以根据消息内容确定数据有效或无效。
示例:旨在作为出生日期的内容 - 您可以从数据中判断它是否有效。
上下文验证 - 您只能通过引用消息来确定内容无效 结合系统状态。
示例:加入公司的有效日期早于出生日期。
对系统说谎 - 您只能在以后的消息中确定消息是错误的 抛出一个异常。
示例:存储的有效出生日期和对出生证明的检查表明这是不正确的。纠正对系统的谎言通常需要在系统之外采取行动,例如援引法律或纪律补救措施。
您的系统必须处理所有类别的错误 - 但在第三种情况下,这可能仅限于发出警报。
相比之下,故障(异常)只有一个原因 - 数据损坏(包括数据截断)。示例:未传递验证参数。
这里适当的机制是故障或异常处理 - 基本上将问题移交给能够处理它的系统的其他部分(这就是为什么应该存在未处理故障的最终目的地)。
答案 3 :(得分:2)
在过去,我们曾经有过一条规则,即异常只适用于特殊和意外的事情。你不想过多使用它们的原因之一是它们“耗费”了很多计算能力。
但是如果你使用例外,你可以减少代码量,不需要很多if else语句,只需让异常冒泡。
这取决于你的项目。最重要的是,有一个项目标准,每个人都以同样的方式做到这一点。
答案 4 :(得分:1)
我的观点是,无论何时该方法应该做什么都不应该抛出异常/错误。所以验证逻辑不应该引发异常,除非无法进行验证(即出于技术原因),但绝不仅仅因为数据无效(在这种情况下,它将返回验证代码/消息或任何帮助调用者纠正数据)。
现在GetMember案例很有意思,因为它完全是关于语义的。方法的名称表明可以通过传递id来检索成员(例如,与TryGetMember方法进行比较)。当然,如果无法找到id,或者数据库没有响应但是传递给此方法的错误id可能是在该调用之前某处出错的迹象,则该方法不应该抛出相同的异常。除非用户可以直接在界面中输入member-id,否则在调用该方法之前应该进行验证。
我听到很多关于性能问题的消息。我只是使用C#和trow / catch 1000异常进行了一个简单的测试。 1K Exeptions花费的时间是23ms。每个例外是23μ。我认为性能不再是这里的第一个参数,除非你计划每秒提高超过2000个异常,在这种情况下你会有5%的性能下降,我可以开始考虑。
我的拙见...