如何在不关闭WCF连接的情况下很好地返回DTO

时间:2011-12-05 08:03:18

标签: wcf channel faultexception

我在C#中的WCF服务看起来像这样。

[ServiceContract]
public class MySecretService
{
      [OperationContract]
      [FaultContract(typeof(ErrorMessage))]
      public MyDTO ReturnMyDTOMethod(int id, out string errorMessage)
      {
        try
        {
           //Do stuff...

           //Do some more stuff... pseudocode
          if (biz rule 1 && etc)
          {
            return MyDTO;
          }
          else if (biz rule 2 && etc)
          {
            return null;
          }
          else
          {
            throw new FaultException<ErrorMessage>(blah etc..)
          }
        }
        catch (Exception e) 
        {
            throw new FaultException<ErrorMessage>(blah etc...);
        }
     }//end-method
}//end-class

从方法返回的DTO如下所示:

[DataContract]
public class MyDTO
{
  [DataMember]
  public XElement XmlRep
  {
    get
    {
        //do something within setter, etc...

    //error occurs prior to returnin from setter, where to i catch it?
    return _xmlRep
    }
    set
    {
    _xmlRep = value;

    }

  }
}

我发现的典型示例显示从方法中抛出FaultException;但就我而言,我的方法没有错误;在将对象返回给客户端/消费者时发生错误;即在序列化DataMember / Property XmlRep时;

所以我不能在我的方法中抛出FaultException;但我仍然想避免得到 “底层连接已关闭:连接意外关闭。”并抛出getter中发生的正确错误。

我没有尝试将try / catch放在MyDTO的getter中,或者我想要因为我希望我的DTO尽可能简单,并且对FaultExceptions和WCF的东西一无所知。还有其他想法吗?

编辑:为了让它更清楚,我知道错误发生在MyDto DataContract的Getter中;但是在其他地方我会抛出FaultException,因为在Getter里面看起来像是一个扔掉它的狡猾的地方?

编辑#2:我在服务端实现了一个全能错误处理程序,如下面Tim所建议的那样(使用IErrorHandler);这在我的具体情况下不起作用。我认为这是因为在OperationContract ReturnMyDTOMethod()中没有出现错误,而是在序列化时在MyDto中发生;换句话说,似乎马已经用螺栓连接(方法返回成功),并且IErrorHandler有任何用处是迟到的 - 具体的ProvideFault()不会触发,但HandleError()会触发。因此,我仍然收到一个频道断开的消息,这需要我回到绘图板 - 即确保MyDto不做任何奇特的事情,例如生成错误!

1 个答案:

答案 0 :(得分:1)

我看到两个选项:

  1. 听起来您的DataContract中的某些内容无法序列化。我会看看那里并确定它是什么,为什么它没有被序列化,如果有其他方法你可以在setter中处理问题。您可以在没有try-catch块的情况下执行此操作,具体取决于它是什么。在没有看到代码或知道实际错误是什么的情况下,很难给出更具体的信息。

  2. 在您的服务中实施IErrorHandler接口。这将捕获任何未处理的异常,并根据您的服务需要处理它们(例如,通过FaultException序列化错误消息)。网上有很多关于如何做到这一点的例子 - 只需google IErrorHandler和WCF。

  3. 我个人倾向于尝试方法#1 - 可能有一个特定的原因(或一组理由)你的DTO没有序列化,我觉得最好在代码中处理这些问题而不是依赖某种方式全局错误处理程序(这将是#2)。

    此外,根据您的setter中的逻辑,您可能已经使DTO变得复杂。我通常会尽量避免使用我的setter中的任何逻辑,除非它像null检查一样简单。

    在第2次问题编辑后添加

    IErrorHandler的文档声明:

    “在调用所有ProvideFault实现并将响应消息传递给通道后,可能会发生异常。如果发生通道异常(,例如,难以序列化消息),则不会通知IErrorHandler对象。在这种情况下,您应该确保您的开发环境捕获并向您显示此类异常,或者使用跟踪来发现问题。“ (强调我的)

    您知道导致序列化失败的原因吗?如果你这样做,我认为你可以在代码本身解决它。你启用了跟踪吗?在我看来,你需要确定你的DTO无法序列化的原因。