WCF服务中处理异常的最佳方法是什么?

24

我有一个WCF服务部署在两台或多台远程计算机上,客户端使用基于桌面的应用程序来访问任何wcf服务。

WCF服务连接到SQL Server 2005以读写数据。这是一个内网场景,客户端应该在同一个域中。

现在可能会出现下列WCF服务抛出异常的情况:

  1. 无效的URL
  2. WCF服务已关闭
  3. SQL Server 2005未运行
  4. 客户端不在同一域中
  5. 认证失败
  6. 授权失败

对于每个异常,我都需要执行一些操作或更新状态栏,具体取决于异常。例如,如果授权失败,我必须提示用户重新输入其凭据。

请建议最佳的设计方法来处理此问题。

4个回答

35

你可以在服务类中捕获和处理所有异常,并将它们转换为 FaultException 或 FaultException 异常。

这样,你就不会“故障”(或拆除)客户端和服务器之间的通信通道。

更好的方法是在你的服务类上实现 IErrorHandler 接口,它提供了一种全局捕获所有异常并提供符合 SOAP 标准的 FaultException 的方式。

你甚至可以将你的 IErrorHandler 转换为可配置的行为,在配置中可以开启或关闭。

查看以下文章和博客获取更多细节:


1
我对IErrorHandler不是很了解,但我读过一些关于使用IErrorHandler的文章和帖子,它们说它有一些缺点。在某些情况下,异常可能直接从WCF服务抛出到客户端。你会推荐我使用IErrorHandler吗? - Ashish Ashu
4
我想他期望过高了 - IErrorHandler 只能捕捉在服务器上发生的所有异常,例如通信错误或安全设置不匹配,并不会在服务器上发生,而是在消息到达服务器之前就已经发生了。这是一种不同的情况。 - marc_s
1
我可以直接指向Rory Primrose的帖子。这是一个完整的工作示例。 - harvest316
@marc_s 我知道这是一个非常古老的线程,但我遇到了完全相同的问题(SecurityExceptions未被IErrorHandler捕获)。您说它不会发生在服务器上,这让我感到困惑。ServiceCredentials行为附加在服务主机中并在服务器上执行(我的WCF跟踪可以很好地捕获异常)。有没有办法捕获这些异常? - MvdD
我如何在客户端高效处理任何类型的错误和异常(我只是消费者,服务器代码超出了我的范围)。请参考我发布的这个问题。 - Shimmy Weitzhandler
显示剩余3条评论

6
  1. 创建一个自定义的故障类,并使用DataContract属性进行标记。
  2. 在服务契约接口上使用FaultContract标记方法。例如:[FaultContract(typeof(CustomFault))]
  3. 在您的服务方法中,捕获任何适用的内部异常并抛出FaultException<CustomFault>。或者,如marc_s所提到的那样,可以使用IErrorHandler将异常映射到故障中。

个人建议,创建一个具有Reason属性的基础Fault类,并从该类扩展所有自定义故障。当要抛出故障时,调用:

throw Fault.Create<CustomFault>(new CustomFault("Boo hoo"));

值得注意的是,我会对我的故障类(包括常见的 Fault 类)进行版本控制,以及所有其他服务。但这只有在服务版本控制是一个问题时才需要考虑。
以下是基本的 Fault 类(为了简洁起见,我删除了参数验证):
[DataContract(Namespace = XmlVersionNamespace.FaultNamespace)]
public abstract class Fault
{
    internal FaultReason Reason { get; set; }

    protected Fault(string reasonText)
    {
        Reason = new FaultReason(new FaultReasonText(reasonText, CultureInfo.CurrentUICulture));
    }

    public override string ToString()
    {
        return Reason.ToString();
    }

    internal static FaultException<TDetail> Create<TDetail>(TDetail fault) where TDetail : Fault
    {
        return new FaultException<TDetail>(fault, fault.Reason);
    }
}

谢谢Richard!如果认证失败,你能否给我一个例子?只需给我类之间的关系以及如何在客户端应用程序上处理即可。 - Ashish Ashu
我将创建一个 AuthenticationFailedFault(从 Fault 扩展它),将消息传递给基本的 Fault 构造函数。在您的客户端应用程序中,您只需捕获 FaultException<AuthenticationFailedFault>,因为只要您使用 [FaultContract] 标记了该方法,AuthenticationFailedFault 就会成为 WSDL 的一部分。 - Richard Szalay

2

您可以为WCF服务中的每个异常场景设计特定的故障数据协定,以便您可以分别在客户端处理故障/异常。


我是新手,你能给我一些链接吗? - Ashish Ashu

1
try
{
  // Actions
}
catch (Exception ex)
{
  // Log the exception
  // Throw Fault Exception back to client
  FaultException fe = new FaultException(ex.Message, new FaultCode("Your fault code"));
  //throw fault exception back to WCF client
  throw fe;
}           

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接