SOAPエラーメッセージ内の複数の名前空間により、FaultExceptionの逆シリアル化が失敗する
-
10-07-2019 - |
質問
Webサービスに接続していますが、返される障害メッセージは(まったく)逆シリアル化されておらず、作成できるクラスのバージョンは正しく逆シリアル化されません。サーバー側を制御することはできません。サーバーは検出を許可しないため、エンドポイントのURLの最後に?WSDLを追加すると、WSDLではなくエラーが発生します。
[Fiddler] [1]は、次のようなエラーメッセージが表示されることを示しています。
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:eGov="http://eGov.gov" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>Client</faultcode>
<faultstring/>
<detail>
<eGov:eGov2Exception>
<eGov:ErrorClassification>SOME_ERROR</eGov:ErrorClassification>
<eGov:ErrorCode>SOME_ERROR_CODE</eGov:ErrorCode>
<eGov:ErrorMessage>Your request was unsuccessful. blah blah blah.</eGov:ErrorMessage>
</eGov:eGov2Exception>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
作成したクラス(xsd.exe、svcutil、およびゼロから作成したコードを含む他のものを試してみてください)では、キャッチしようとしたときにデシリアライズできません:
catch (FaultException<eGov2ExceptionType> exp)
{
// Never stops here.
}
catch (FaultException<AllOtherAttemptedClasses> exp)
{
// Never stops here.
}
catch (SoapException se)
{
// Never stops here.
}
catch (FaultException exp)
{
//Always gets caught here.
}
ベースのFaultExceptionキャッチのみが呼び出されます。つまり、送信されているFaultMessageの内容が失われます。私が書いたクラスのいくつかは、上記のサンプルに非常に密接にシリアライズされますが、デシリアライズに失敗するため、私たちの疑いは、名前空間の問題があることです。
質問:
1-これをどのように書きますか?
2-これはWCFの一般的なエラー/問題ですか?
[1]: http://www.fiddler2.com/fiddler2/ Fiddler
解決
私たちがやったことは、 Fault をキャッチしてSOAPチャネルに返そうとするのをやめることでした。代わりに、カスタム例外を作成し、 MessageInspector を接続して障害を監視し、例外としてスローします。
(サニタイズされた)コードの関連部分:
public void AfterReceiveReply(ref Message reply, object correlationState)
{
if (reply.IsFault)
{
XmlDictionaryReader xdr = reply.GetReaderAtBodyContents();
XNode xn = XDocument.ReadFrom(xdr);
string s = xn.ToString();
XDocument xd = XDocument.Parse(s);
XNamespace nsSoap = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace ns = "http://eGov.gov";
XElement xErrorClass = xd.Element(nsSoap + "Fault").Element("detail").Element(ns + "eGov2Exception").Element(ns + "RequestErrorClassification");
XElement xErrorCode = xd.Element(nsSoap + "Fault").Element("detail").Element(ns + "eGov2Exception").Element(ns + "RequestErrorCode");
XElement xErrorMessage = xd.Element(nsSoap + "Fault").Element("detail").Element(ns + "eGov2Exception").Element(ns + "RequestErrorMessage");
throw new eGovException(xErrorClass.Value, xErrorCode.Value, xErrorMessage.Value);
}
}
メインアプリケーションは次を使用します:
catch(eGovException ex)
{
//ここで例外を処理します。
}
名前空間を修正するために多くの時間が浪費されました。回答ありがとうございます。
他のヒント
シリアル化が完全に失敗した場合にこれを処理する1つの方法は、メッセージを入力および出力として入力します。この方法では、Iffault == trueのときにXMLを手動で解析するか、GetBody()を使用してエラーが発生しなかった場合に通常のコンテンツを取得できます。
まず、このWebサービスを作成した人々からWSDLを取得できない場合、SOAPベースのWebサービスを持つビジネスはありません。適切なWSDLは、「?WSDL」かどうかにかかわらず、問題を解決します。使用されます。
次に、 eGov2ExceptionType
クラスのコードを投稿してください。 http://eGov.gov
名前空間が設定されていないようです。