1

サードパーティサーバーからのwsdlがあります。svcutilを実行し、一連の

XmlNode AMethod(object Request);

メソッド。各メソッドの応答/要求オブジェクトを説明する個別の100ページのPDFがあります

私の考えは、Webメソッドをラップし、XmlSerializerを使用して強く型付けされたオブジェクトを返すことでした。返されるxmlは次のようになります(soapヘッダーを削除しました):

<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:type="ResponseExt" 
        xmlns="http://www.thirdparty.com/lr/">
  <Code>0</Code>
  <Message>SUCCESS</Message>
  <SessionId>session_token</SessionId>
</Response>

シンプルに見えた。クラスを作成しました(ドキュメント/ワイヤーキャプチャから):

[XmlRoot("Response")]
//EDIT added XmlType
[XmlType("ResponseExt", Namespace = "http://www.thirdparty.com/lr/")]
public class MyClass {
    public string Code {get; set;}
    public string Message {get; set;}
    public string SessionId {get; set;}
}

処理時間:

//XmlNode node = xml from above
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
XmlNodeReader reader =  new XmlNodeReader(node);
Myclass myclass = serializer.Deserialize(reader) as MyClass

最後の行は、内部例外メッセージで爆発します:指定されたタイプは認識されませんでした:name ='ResponseExt' namespace =' http://www.thirdparty.com/lr/'、at<Response xmlns='' >。
シリアライザーを幸せにする方法と、この2つが正確に何を意味するのか理解できません

xsi:type = "ResponseExt" xmlns = "http://www.thirdparty.com/lr/

いつものように、アドバイスやポインタは大歓迎です


編集:以下の受け入れられた答え。

これを見つけるまで、私はまだ例外を取得していました。うまくいけば、誰かの時間を節約できるでしょう。私は後ろ向きに働き始めました。ワイヤー上でキャプチャされたxml。正しい属性で作成したクラスに逆シリアル化:魅力のように機能しました。Webサービスから再試行しました-例外。何らかの理由で、XmlSerializerはResponseExtを認識しません。

XmlSerializer serializer = new XmlSerializer(typeof(Response));
XmlNode node = (XmlNode)results[0];
XmlDocument doc = new XmlDocument();
doc.LoadXml(node.OuterXml); //reload node
XmlNodeReader reader = new XmlNodeReader(doc.FirstChild); //there is only one node
Response rsp = serializer.Deserialize(reader) as Response; //works

編集:根本的な問題のwsdlファイルが完全ではありませんでした。これに2日間を費やし、この(醜い)回避策を見つけた後、サードパーティベンダーはエラーなしで逆シリアル化するすべてのタイプの完全なWSDLを提供しました。

4

1 に答える 1

1

WSDLがあるのに、なぜ手動でXMLを逆シリアル化するのですか?

WSDLを使用している場合は、svcutil.exeツールまたはwsdl.exeツールを使用して、ネットワーク上で送受信されるXMLメッセージのプロキシークラスとDTOを生成します。

Webサービスツールキット、つまり「スタック」のポイントは、これを提供することです。これにより、クラスやXMLシリアル化コードを手動で作成する必要がなくなります。

これを試しましたか?これらのツールの1つを使用してWSDLを実行しようとしましたか?または、Visual Studioで「Web参照を追加」しようとしましたか?


質問を更新した後、カスタムコードを作成するのではなく、WSDLを変更することをお勧めします。サービスのカスタムWSDLを作成できます。これにより、必要なプロキシクラスが正しく生成されます。100個すべてのメソッドが必要でない場合(またはいくつでもある場合)は、それらを除外します。メソッドからカスタムオブジェクトが必要な場合は、そのオブジェクトに対応するcomplexTypeを定義します。これは、各メソッドのXML逆シリアル化コードを手動で作成するよりもはるかに簡単で信頼性があります。


そのアイデアが気に入らず、XML逆シリアル化コードを手動で記述したい場合は、次の2つのことを行う必要があります。

  1. XmlRoot属性に名前空間をアタッチします。

  2. クラスの名前をに変更し、という名前のクラスからResponseExt派生させResponseます。そのResponseクラスをXmlInclude属性で装飾します。これにより、Xmlシリアライザーの使用がXMLフラグメントで使用されるxsi:typeと一致します。

コードでは次のようになります。

[XmlRoot("Response", Namespace="http://www.thirdparty.com/lr/")]
public class ResponseExt : Response {
}

[XmlRoot("Response", Namespace="http://www.thirdparty.com/lr/")]
[XmlInclude(typeof(ResponseExt))]
public class Response {
    public string Code {get; set;}
    public string Message {get; set;}
    public string SessionId {get; set;}
}

public class XsiType
{
    public static void Main(string[] args)
    {
        try
        {
            string filename = "XsiType.xml";
            XmlSerializer s1 = new XmlSerializer(typeof(Response));
            ResponseExt r = null;
            using(System.IO.StreamReader reader= System.IO.File.OpenText(filename))
            {
                r= (ResponseExt) s1.Deserialize(reader);
            }

            var builder = new System.Text.StringBuilder();
            var xmlws = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
            using ( var writer = System.Xml.XmlWriter.Create(builder, xmlws))
            {
                //s1.Serialize(writer, r, ns);
                s1.Serialize(writer, r);
            }
            string xml = builder.ToString();
            System.Console.WriteLine(xml);

        }
        catch (System.Exception exc1)
        {
            Console.WriteLine("Exception: {0}", exc1.ToString());
        }
    }
}

関連:xsi:type属性の使用を強制するにはどうすればよいですか?

于 2010-04-07T00:34:01.787 に答える