【问题标题】:WCF: SOAP Fault or normal Exception(s) in DataContract classWCF:DataContract 类中的 SOAP 错误或正常异常
【发布时间】:2011-03-29 16:41:57
【问题描述】:

我的 Service 的 OperationContract 的主要参数是一个名为 Preapproval 的类。在 Preapproval 类中,有一些用于 DataMember 属性的公共 getter/setter。我有验证设置器输入的代码,这样我会抛出 ArgumentException,如果说参数为空白或超出域的正确范围。

如果输入无效,我通常会在这里抛出 ArgumentException。由于这是 WCF 情况,我是否必须在此处抛出预定义的 FaultException 而不是 ArgumentException?我知道,在其他地方,我可能会捕获一般异常并将它们作为 FaultExceptions 重新抛出,但此活动将发生在堆栈的更高层,在 WCF 管道自动执行的某些工作中。

例如,当调用者调用我的服务时,序列化程序将反序列化他们的 SOAP,尝试调用我的对象上的设置器,并在实际调用我的操作之前体验到 ArgumentException 的抛出。因此,在 DataContract 类中,简单地立即抛出 FaultExceptions 是一种好的设计实践吗?我真的不想将自定义处理程序连接到通道调度程序。

我知道我可以直接抛出 FaultExceptions,但我真的很想将这类事情限制在服务中。如果无法避免,我也可以在支持类中进行,但我希望尽可能编写典型的代码,与 System.ServiceModel 等没有那么紧密的耦合。

谢谢!

【问题讨论】:

  • 使用FaultContractAttribute怎么样?
  • 当然,这是我们正在探索的一个选项。我的问题更像是最佳实践。例如,在我们用作服务参数的类中,在它的设置器中,如果我们必须抛出异常,我们是否应该抛出 FaultException,而不是 ArgumentException?通常,我们希望将尽可能少的东西耦合到 WCF 框架,但是看看这些东西是如何用 DataContract 和 DataMember 属性标记的,也许这一点没有实际意义。
  • 如果有人读到这篇文章,我决定采用更简单的方法,只将原始类型参数传递给服务,而不是 Preapproval 对象。这样,服务本身可以验证输入并抛出适当的 FaultException。对于这种单一方法的服务,EAB 在这里被证明是矫枉过正。

标签: wcf web-services soap fault faultexception


【解决方案1】:

我会将 FaultExceptions 排除在您的 DataContract 类之外——您可能希望在 WCF 上下文之外使用这些类。

防止 WCF 特定代码潜入您的 DataContracts(除了属性)的一种方法是让 DataContract 类引发异常,并在服务层使用 Enterprise Library's WCF Exception Shielding 将这些异常映射到故障协定。

基本上企业库实现IErrorHandler 并将异常转换为故障异常。我认为处理程序是实现您想要的唯一方法(因为您的服务中不会引发异常)。好消息是,您真的不需要做太多事情就能让它发挥作用。

只需为您的服务添加一个属性:

[ServiceContract]
[ExceptionShielding]
public interface IApproval
{
    [OperationContract]
    [FaultContract(typeof(ApplicationServiceFault))]
    [FaultContract(typeof(SystemServiceFault))]
    void PreApprove(Preapproval preapproval);
}

然后添加一些配置(省略配置以节省空间)以将异常映射到 FaultContract。请注意,您的操作仍然必须声明 FaultContracts。

【讨论】:

  • 谢谢;这更符合我的问题,因为我们希望保持类而不是框架不可知论。因此,由于我们在 setter 中抛出 ArgumentException,我们需要一种方法来确保它被正确映射。我会看看这个异常屏蔽。谢谢你。有机会我会第一时间更新的。
  • 这看起来像是要走的路。我特别想知道当无效参数传递给服务时会发生什么。顺便说一句,这行研究将我引向了验证块,这也是一个不错的功能。或许两者的共同作用将是干净的 WCF 参数验证的最终解决方案。
  • @Pittsburgh DBA:让 VAB 在您所说的模型中工作会有点痛苦。您可能必须为每个属性创建一个规则集,并让每个 setter 调用 Validate 方法。此外,在您当前的方法中,如果您在 setter 上进行验证,那么一旦一个 setter 获得无效值,您将抛出异常,因此用户一次只会收到一条错误消息。这可能不是用户希望看到的。
【解决方案2】:

您的PreApproval 类不应该知道它正在Web 服务中使用。如果从任何其他类型的应用程序调用它,让它抛出它会抛出的任何异常。

您的服务的“顶级”应该捕获异常并将它们转换为适当的FaultException

【讨论】:

  • 正如我所说,这是不可行的,因为它不是我们的代码,而是 WCF 内部,它反序列化调用者的 SOAP,从而调用我们 DataContract 类的设置器。也许我没有很好地解释这一点。当然,我们可以左右捕获异常,并抛出相应的 FaultException。我们不能在服务代码之前执行的 WCF 管道中执行此操作。
  • @Pitt:setter 会抛出异常。
  • @John Saunders:setter 确实会抛出异常,它们抛出的异常类型是 ArgumentException。这是因为它们是通用类,并且不依赖于 WCF 依赖项。因此,当调用服务时,setter 抛出它们的异常,它会导致问题,因为除非我们使用 ExceptionShielding,否则这发生在堆栈上太远,我们无法捕获并随后抛出一个 FaultException,就像我们希望的那样。
  • 看看实现IErrorHandler 接口。这就是它的用途。
  • 谢谢。这会比使用企业异常处理应用程序块更好吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-15
相关资源
最近更新 更多