我正在与一位同事讨论何时扔出故障以及何时不在WCF服务中丢下故障。

一种观点是,我们只有由于某些错误而无法完成其工作时,我们只会抛出故障。因此,某些事情可能处于无效状态。因此,一些例子:

  • validatemember(字符串名称,字符串密码,字符串country) - >如果不传递强制性参数,则会丢弃故障,因为验证本身无法执行; - >如果发生某些内部错误,例如数据库被关闭 - >在所有其他情况下都会返回状态合同,以指定验证结果(成员validated,forge,错误password,membernotnoing,...)

  • getMember(int memberId) - >只有在某些情况下出现的情况下才会抛出故障,在所有其他情况下,它将返回会员或无效的情况

另一个意见是,当GetMember找不到成员时,或者在valialatemberm的情况下,密码是错误的。

你怎么看?

有帮助吗?

解决方案

我对此的看法...

失败有三个原因:

  1. 服务代码引发了一个异常,例如数据库错误,代码中的逻辑错误。这是你的错。
  2. 客户端代码无法根据您的文档正确使用您的服务,例如,它没有设置所需的标志值,因此未能通过ID。这是客户端软件开发人员的错。
  3. 最终用户在屏幕上输入了一些愚蠢的东西,例如缺少出生日期,负薪负数。这是最终用户的错。

这取决于您如何选择将实际故障合同映射到每个故障原因。例如,我们这样做:

  • 对于原因1和2,所有客户端代码都需要知道的是服务失败。我们定义了一个非常简单的“致命错误”故障合同,该合同仅包含唯一的错误ID。该错误的完整详细信息已记录在服务器上。
  • 对于原因3,最终用户需要确切知道他/她做错了什么。我们定义一个“验证错误”故障合同,其中包含友好错误消息的集合,以在屏幕上显示客户代码。

我们借了 Microsoft Entlib类 为3,并使用 异常屏蔽 宣称处理1和2的原因。它制作了非常简单的代码。

澄清:

我们在服务中处理这样的三个原因:

  1. 服务代码中提出了意外的例外。我们在最高级别上捕获它(实际上例外屏蔽会抓住它,但原理是相同的)。登录完整的详细信息,然后扔一个 FaultException<ServiceFault> 仅包含错误ID的客户端。
  2. 我们验证输入数据并故意提出例外。通常是 ArgumentException, ,但是任何合适的类型都会做。抛出后,它的处理方式与(1)完全相同,因为我们希望使客户看起来相同。
  3. 我们验证输入数据并故意提出例外。这次,这是一个 FaultException<ValidationFault>. 。我们配置异常屏蔽以通过未包装传递该屏蔽,因此在客户端上显示为 FaultException<ValidationFault> 不是 FaultException<ServiceFault>.

最终结果:

  • 服务内部根本没有捕获块(不错的干净代码)。
  • 客户只需要抓住 FaultException<ValidationFault> 如果要向用户显示消息。所有其他异常类型,包括 FaultException<ServiceFault> 客户的全局错误处理程序作为致命错误处理,因为服务中的致命错误通常也意味着客户端的致命错误。

其他提示

这是一个常见的例行失败,然后扔错是一个错误。该软件应编写以处理常规项目,例如输入错误的密码。故障处理是出于特殊故障,这不被认为是该程序正常设计的一部分。

例如,如果您的程序的编写为始终可以访问数据库并且数据库不可访问的想法,那么“修复”符合您软件限制的问题。应该抛出故障。

故障处理使用不同的逻辑流贯穿编程语言的结构,并且仅在“丢弃”编程问题的正常处理时使用它,您将使解决方案以某种方式利用编程语言的功能似乎更自然。

我相信分开错误处理和故障处理是一个好习惯。任何错误案例都应通过您的程序处理 - 为特殊条件保留故障处理。作为两者分离的指南,我在考虑此类情况时发现只有三种类型的错误(处理数据和消息时)和仅一种类型的故障时,我发现这很有用。错误类型与不同类型的验证相关:

  1. 消息验证 - 您可以从消息内容确定数据有效或无效。

    示例:旨在作为出生日期的内容 - 您可以从数据中分辨出是否有效。

  2. 上下文验证 - 您只能通过引用与系统状态的消息来确定内容无效。

    示例:加入公司的有效日期早于该人的出生日期。

  3. 躺在系统中 - 您只能确定当以后的消息引发异常时,消息是错误的。

    示例:有效的出生日期存储并检查了该人的出生证明这是不正确的。对系统的校正通常需要在系统之外采取行动,例如调用法律或纪律补救措施。

您的系统必须处理所有类别的错误 - 尽管在三个例子中,这可能仅限于发出警报。

相比之下,故障(例外)仅具有一个原因 - 数据损坏(包括数据截断)。示例:未传递验证参数。

在这里,适当的机制是故障或异常处理 - 基本上将问题交给了能够处理它的系统的其他部分(这就是为什么应该有无与伦比的故障的最终目的地的原因)。

在过去,我们曾经有一条规则,即例外仅适用于特殊和意外的事情。您不想使用它们太多的原因之一是它们“成本”了很多计算能力。

但是,如果您使用异常,则可以减少代码量,而无需大量的否则语句,只需让异常泡泡起来。

这取决于您的项目。最重要的是有一个项目标准,每个人都以相同的方式做到这一点。

我的看法是,只要无法实现该方法,就应该抛出例外/错误。因此,验证逻辑绝不应提高异常,除非无法进行验证(即出于技术原因),但绝不只是因为数据无效(在这种情况下,它将返回验证代码/消息或任何帮助呼叫者纠正验证者的验证代码/消息数据)。

现在,GetMember的情况是一个有趣的情况,因为这一切都与语义有关。该方法的名称表明可以通过传递ID来检索成员(比较典范的TryGetmember方法)。当然,如果找不到ID,或者数据库未响应,则该方法不应抛出相同的异常,但传递给此方法的错误ID可能是该呼叫之前某个地方出现问题的迹象。除非用户可以直接从接口内输入成员ID,在这种情况下应在调用该方法之前进行验证。

我听到了很多有关性能问题的信息。我刚刚使用C#和Trow/Catch 1000异常进行了简单的测试。 1k exeptions的时间为23ms。每个例外是23µ。我认为性能不再是第一个参数,除非您打算每秒提高2000多个例外情况,在这种情况下,您将降低5%的性能,我可以开始考虑。

我的卑鄙看法...

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top