9


2

FaultException.Detailが空に戻ってくる

WCFクライアントで特定のFaultExceptionをキャッチしようとしています。 基本的に、障害クラスから内部記述を抽出する必要があります。そうすれば、上位層が何でもできるように別の例外にパッケージ化できます。

私はこれを何度も成功させましたが、今回の違いは、例外がスローされるメソッドの上で宣言されたサービス参照属性からわかるように、フォールトが配列として宣言されていることです。

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

これは私のコードです:

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

問題は、WCFトレースからのSOAP応答でデータ(説明フィールドなど)を見ることができる場合でも、コードで*詳細(配列)が常に空に戻ってくることです。

必要なものは間違いなく戻ってきますが、何らかの理由でデシリアライズされないか、コードからアクセスできません。

どんな助けにも感謝します!

更新

@Darinの提案を試してみましたが、運がありません。XmlReaderから抽出している文字列は「/ r / n」です。

var sb = new StringBuilder();

using (XmlReader reader = fault.GetReaderAtDetailContents())
{
  while (reader.Read())
     sb.AppendLine(reader.ReadOuterXml());
}

var detail = sb.ToString();

詳細セクションがまったく表示されないようです!

5 Answer


8


UPSフォーラムで解決策を見つけました。

「問題は、Visual StudioがErrorDetailオブジェクトを正しくマップしなかったことでした。 ErrorDetailノードは「ErrorDetail」と呼ばれますが、そのために生成されるタイプは「ErrorDetailType」です。使用していた各サービスに対して生成されたreference.csクラスを編集し、TypeNameを追加しました: "


5


問題がどこにあるかを言うのは難しいですが、喫煙銃はこの軸Webサービスが標準メッセージを生成していないのではないかと思います。 これを回避する1つの方法は、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.
    }
}


2


できる限りシンプルなテストケースを思いつきました。 お役に立てば幸いです。 サーバ側:

[ServiceContract]
public interface IService1
{
    [OperationContract]
    [FaultContract(typeof(FaultClass[]))]
    string Crash();
}

public class Service1 : IService1
{
    public string Crash()
    {
        var exception = new FaultException(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 e)
{
    //Break here
}


2


文字列として「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()`は、新しい行を含む全体を取得しているように見えますが、これは私が望んでいたものです。


1


障害(具体的にはスタックトレース)を使用してデータを通信しようとしても、同様の状況がありました。 https://stackoverflow.com/questions/4888713/wcf-faultcontract-fails-with-namedpipe/4901733#4901733 [この質問]を参照してください。 シリアル化可能な独自のスタックトレースを作成し、それを派生したFaultExceptionクラスに含めることで解決しました。