2008-08-27 19 views
4

Help! Axis WebサービスがC#アプリケーションで使用されています。長い値の配列が常に[0,0,0,0](右の長さ)として出てくるが、値はデシリアライズされません。私は他のプリミティブ(int、double)で試してみましたが、同じことが起こります。私は何をしますか?私は私のサービスのセマンティクスを変えたくありません。.NETがプリミティブ配列をWebサービスから非直列化しないのはなぜですか?

答えて

6

ここで私は結局何をしましたか。私はこれのためにそこに別の解決策を見つけたことはありませんので、もしあなたが何か良いものを持っていれば、是非貢献してください。

まず、WSDLの長い配列定義:タイプエリア:

<xsd:complexType name="ArrayOf_xsd_long"> 
    <xsd:complexContent mixed="false"> 
     <xsd:restriction base="soapenc:Array"> 
     <xsd:attribute wsdl:arrayType="soapenc:long[]" ref="soapenc:arrayType" /> 
     </xsd:restriction> 
    </xsd:complexContent> 
    </xsd:complexType> 

次に、我々は修正を行いますSoapExtensionAttributeを作成します。問題は、.NETがdouble値を含む要素に複数のIDを追いかけることがなかったことです。そこで、我々は値を探しに行く、配列項目を処理して、要素に値を挿入します。

[AttributeUsage(AttributeTargets.Method)] 
public class LongArrayHelperAttribute : SoapExtensionAttribute 
{ 
    private int priority = 0; 

    public override Type ExtensionType 
    { 
     get { return typeof (LongArrayHelper); } 
    } 

    public override int Priority 
    { 
     get { return priority; } 
     set { priority = value; } 
    } 
} 

public class LongArrayHelper : SoapExtension 
{ 
    private static ILog log = LogManager.GetLogger(typeof (LongArrayHelper)); 

    public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute) 
    { 
     return null; 
    } 

    public override object GetInitializer(Type serviceType) 
    { 
     return null; 
    } 

    public override void Initialize(object initializer) 
    { 
    } 

    private Stream originalStream; 

    private Stream newStream; 

    public override void ProcessMessage(SoapMessage m) 
    { 
     switch (m.Stage) 
     { 
      case SoapMessageStage.AfterSerialize: 
       newStream.Position = 0; //need to reset stream 
       CopyStream(newStream, originalStream); 
       break; 

      case SoapMessageStage.BeforeDeserialize: 
       XmlWriterSettings settings = new XmlWriterSettings(); 
       settings.Indent = false; 
       settings.NewLineOnAttributes = false; 
       settings.NewLineHandling = NewLineHandling.None; 
       settings.NewLineChars = ""; 
       XmlWriter writer = XmlWriter.Create(newStream, settings); 

       XmlDocument xmlDocument = new XmlDocument(); 
       xmlDocument.Load(originalStream); 

       List<XmlElement> longArrayItems = new List<XmlElement>(); 
       Dictionary<string, XmlElement> multiRefs = new Dictionary<string, XmlElement>(); 
       FindImportantNodes(xmlDocument.DocumentElement, longArrayItems, multiRefs); 
       FixLongArrays(longArrayItems, multiRefs); 

       xmlDocument.Save(writer); 
       newStream.Position = 0; 
       break; 
     } 
    } 

    private static void FindImportantNodes(XmlElement element, List<XmlElement> longArrayItems, 
              Dictionary<string, XmlElement> multiRefs) 
    { 
     string val = element.GetAttribute("soapenc:arrayType"); 
     if (val != null && val.Contains(":long[")) 
     { 
      longArrayItems.Add(element); 
     } 
     if (element.Name == "multiRef") 
     { 
      multiRefs[element.GetAttribute("id")] = element; 
     } 
     foreach (XmlNode node in element.ChildNodes) 
     { 
      XmlElement child = node as XmlElement; 
      if (child != null) 
      { 
       FindImportantNodes(child, longArrayItems, multiRefs); 
      } 
     } 
    } 

    private static void FixLongArrays(List<XmlElement> longArrayItems, Dictionary<string, XmlElement> multiRefs) 
    { 
     foreach (XmlElement element in longArrayItems) 
     { 
      foreach (XmlNode node in element.ChildNodes) 
      { 
       XmlElement child = node as XmlElement; 
       if (child != null) 
       { 
        string href = child.GetAttribute("href"); 
        if (href == null || href.Length == 0) 
        { 
         continue; 
        } 
        if (href.StartsWith("#")) 
        { 
         href = href.Remove(0, 1); 
        } 
        XmlElement multiRef = multiRefs[href]; 
        if (multiRef == null) 
        { 
         continue; 
        } 
        child.RemoveAttribute("href"); 
        child.InnerXml = multiRef.InnerXml; 
        if (log.IsDebugEnabled) 
        { 
         log.Debug("Replaced multiRef id '" + href + "' with value: " + multiRef.InnerXml); 
        } 
       } 
      } 
     } 
    } 

    public override Stream ChainStream(Stream s) 
    { 
     originalStream = s; 
     newStream = new MemoryStream(); 
     return newStream; 
    } 

    private static void CopyStream(Stream from, Stream to) 
    { 
     TextReader reader = new StreamReader(from); 
     TextWriter writer = new StreamWriter(to); 
     writer.WriteLine(reader.ReadToEnd()); 
     writer.Flush(); 
    } 
} 

最後に、我々が長い列をデシリアライズされますReference.csファイル内のすべてのメソッドにタグを付けます私たちの属性:

この修正は長いものですが、この問題が発生しているプリミティブ型を処理するために一般化される可能性があります。より良い代替手段を提供することがあり、このリンクが見つかり

+0

魅力的なように機能しますが、生成されたコードを変更して属性を追加する必要があります – Luuk

3

は、ここで私は件名に書いたblog postの多かれ少なかれコピー、貼り付けたバージョンです。

要約:.NETが結果セットを逆シリアル化する方法(上記のChrisのソリューションを参照)を変更することも、.NET SOAP実装と互換性のある方法でAxisを再構成して結果をシリアル化することもできます。

あなたは後者のルートを行く場合は、ここに方法は次のとおりです。

...生成 クラスが見えると、通常 を機能するように見えるが、あなたは、クライアント に 非直列化された配列を見てみましょう場合 配列が逆シリアル化されており、 配列内のすべての値が0であることがわかります。 によって返されたSOAP応答を確認する必要があります。どうしましたか;あなたがAxisは が 返された要素に値を直接生成するが、ために代わり 参照外部要素ないことに気づくでしょう

<?xml version="1.0" encoding="UTF-8"?> 
<soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/> 
    <soapenv:Body> 
     <doSomethingResponse> 
      <doSomethingReturn> 
      <doSomethingReturn href="#id0"/> 
      <doSomethingReturn href="#id1"/> 
      <doSomethingReturn href="#id2"/> 
      <doSomethingReturn href="#id3"/> 
      <doSomethingReturn href="#id4"/> 
      </doSomethingReturn> 
     </doSomethingResponse> 
     <multiRef id="id4">5</multiRef> 
     <multiRef id="id3">4</multiRef> 
     <multiRef id="id2">3</multiRef> 
     <multiRef id="id1">2</multiRef> 
     <multiRef id="id0">1</multiRef> 
    </soapenv:Body> 
</soapenv:Envelope> 

: は、ここではサンプルの応答(再び、 を明確にするために編集)です 値。これは(と伝えのgSOAPと 古典的な.NETのWeb参照などもして)場合は、これが適切にWCF basicHttpBinding プロバイダによって処理さ ないものは何でも 比較的少数の離散値への多くの参照がある 感覚が、 を作るかもしれません。 次のパラメータ 編集Axisのデプロイメントの server-config.wsddファイルおよび見つける:falseに

<parameter name="sendMultiRefs" value="true"/> 

変更して、 を

それは解決策を見つけるために私にしばらく時間がかかりましたコマンドラインで (Windowsでは)何か のように再デプロイしてください:

java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient server-config.wsdl 

Webサービスの 応答は、今あなたの.NETクライアントによって deserializableでなければなりません。

関連する問題