代码之家  ›  专栏  ›  技术社区  ›  JohnIdol

FaultException.Detail返回空

  •  9
  • JohnIdol  · 技术社区  · 14 年前

    我试图在WCF客户端上捕获给定的FaultException。我基本上需要从fault类中提取一个内部描述,这样我就可以将它打包到另一个异常中,以便上层执行任何操作。

    我已经成功地做了很多次了,这次的不同之处在于,fault被声明为一个数组,您可以从抛出异常的方法顶部声明的service reference属性中看到:

    [System.ServiceModel.FaultContractAttribute(typeof(FaultClass[]), Action = "http://whatever/", Name = "whateverBusinessFault")] 
    

    这是我的代码:

    try
    {
      // call service here
    }
    catch (FaultException<FaultClass[]> ex)
    {
      if (ex.Detail != null && ex.Detail.Length > 0)
      {
        throw new CustomException(ex.Detail[0].description);
      }
      else
      {
        throw;
      }
    }
    

    问题是 细节(数组)总是空的 在代码中,即使我可以看到来自WCF跟踪的SOAP响应中的数据(描述字段等)。

    所以我需要的东西肯定会回来,但出于某种原因,要么它没有被反序列化,要么我无法从代码中得到它。

    感谢任何帮助!

    更新 :

    尝试@Darin suggestion,但没有成功,我从XmlReader中提取的字符串是“/r/n”:

    var sb = new StringBuilder();
    
    using (XmlReader reader = fault.GetReaderAtDetailContents())
    {
      while (reader.Read())
         sb.AppendLine(reader.ReadOuterXml()); 
    }
    
    var detail = sb.ToString();
    

    看起来细节部分一点都没有!

    5 回复  |  直到 14 年前
        1
  •  9
  •   ychapados    8 年前

    我在UPS论坛上找到了解决方案:

    https://developerkitcommunity.ups.com/index.php/Special:AWCforum/st/id371

    “问题是visual studio没有很好地映射ErrorDetail对象。ErrorDetail节点称为“ErrorDetail”,但为其生成的类型为“ErrorDetail type”。我编辑了为我使用的每个服务生成的reference.cs类,并添加了一个类型名:

        2
  •  5
  •   JohnIdol    14 年前

    很难说问题在哪里,但我怀疑冒烟的是这个轴Web服务没有生成标准消息。解决此问题的一种方法是自己解析XML:

    try
    {
        proxy.CallSomeMethod();
    }
    catch (FaultException ex)
    {
        var fault = ex.CreateMessageFault();
        using (XmlReader reader = fault.GetReaderAtDetailContents())
        {
            // TODO: read the XML fault and extract the necessary information.
        }
    }
    
        3
  •  2
  •   Johann Blais    14 年前

    我想出了最简单的测试用例。我希望它能帮助你。 服务器端:

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        [FaultContract(typeof(FaultClass[]))]
        string Crash();
    }
    
    public class Service1 : IService1
    {
        public string Crash()
        {
            var exception = new FaultException<FaultClass[]>(new FaultClass[] { new FaultClass { Data = "TEST" } }, new FaultReason("Boom"));
    
            throw exception;
        }
    }
    
    [DataContract]
    public class FaultClass
    {
        [DataMember]
        public string Data { get; set; }
    }
    

    客户端:

    try
    {
        using (var client = new Service1Client())
        {
            client.Crash();
        }
    }
    catch(FaultException<FaultClass[]> e)
    {
        //Break here
    }
    
        4
  •  2
  •   Dan Stevens    8 年前

    我花了很长时间才想出如何从 FaultException 作为一根绳子。我最终发现了这一点,并编写了这个扩展方法:

    public static string GetDetail(this FaultException faultException)
    {
        if (faultException == null)
            throw new ArgumentNullException(nameof(faultException));
    
        MessageFault messageFault = faultException.CreateMessageFault();
        if (messageFault.HasDetail) {
            using (XmlDictionaryReader reader = messageFault.GetReaderAtDetailContents()) {
                return reader.ReadContentAsString();
            }
        }
        return null;
    }
    

    最初我用的是 reader.Value 但这只出现在返回多行详细信息消息的第一行。 reader.ReadContentAsString() 似乎得到了整件事,包括新线,这是我想要的。

        5
  •  1
  •   Community datashaman    7 年前

    在尝试用错误(特别是堆栈跟踪)来传递数据时,我遇到了类似的情况。见 this question . 我最终通过创建自己的可序列化堆栈跟踪并将其包含在派生的FaultException类中来解决它。