2012-03-13 1 views
3

SOAPサービスに接続する状況があります。私はそのレスポンスの出力を複製する必要がWCFコンテナなしで配列またはコレクションをシリアライズ

<SomeObject> 
    <item1>1</item1> 
    <thing1>2</thing1> 
    <arrayItem><foo>text</foo></arrayItem> 
    <arrayItem><foo>text1</foo></arrayItem> 
    <arrayItem><foo>text2</foo></arrayItem> 
</SomeObject> 

我々は取り戻す応答は次のようになります。私が取り組んでいる問題は、が<arrayItemList>でカプセル化されており、実際には<arrayItemList>がなくて済むことです。

私が受け取っているオブジェクトを適切にシリアル化/逆シリアル化するために私のWCFオブジェクトを置くことができる人はいますか?

EDIT

私が働いているオブジェクトは、このようなものです:

[DataContract] 
public class SomeObject 
{ 
    [DataMember(Order = 0)] 
    public string item1 {get;set;} 

    [DataMember(Order = 1)] 
    public string thing1 {get;set;} 

    [DataMember(Order = 2)] 
    public List<arrayItem> {get;set;} 
} 

[DataContract] 
public class arrayItem 
{ 
    [DataMember] 
    public string foo {get;set;} 
} 

答えて

4

残念ながら、私はこれに最適なソリューションを見つけることができませんでした。しかし、私は実行可能な解決策を見つけました。

警告 - 可能であれば、このソリューションの必要性を防ぐためにWSDLを修正するようにしてください。これはハックのほうが多く、提案された解決策ですが、ピンチで動作します。

解決策は、IClientMessageInspectorとIEndpointBehaviorを実装することでした。これらのインタフェースにより、未処理のテキスト要求および応答にアクセスできます。これらは、メッセージがサービスに送信される前に、またはWCFによって直列化解除される前に、メッセージの変更を許可しました。以下は私の実装と、メッセージに必要な変更を可能にするカスタムクラスです。私が言ったように

public class MyService : IClientMessageInspector 
{ 
    public void DoWork() 
    { 
     // Do some stuff 
    } 

    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState) 
    { 
     string message = reply.ToString(); 

     // Load the reply message in DOM for easier modification 
     XmlDocument doc = new XmlDocument(); 
     doc.Load(reply.GetReaderAtBodyContents()); 

     // Perform the modification 
     MessageHelper.FixArrays(doc); 

     // Create New Message 
     XmlNodeReader reader = new XmlNodeReader(doc.DocumentElement); 
     Message newMsg = Message.CreateMessage(reply.Version, reply.Headers.Action, reader); 

     // Preserve the headers of the original message 
     if (reply.Headers.Any()) 
      newMsg.Headers.CopyHeaderFrom(reply, 0); 

     foreach (string propertyKey in reply.Properties.Keys) 
     { 
      newMsg.Properties.Add(propertyKey, reply.Properties[propertyKey]); 
     } 

     // Close the original message and return new message 
     reply.Close(); 
     reply = newMsg; 
    } 

    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) 
    { 
     return null; 
    } 
} 

public static class MessageHelper 
{ 
    public static void FixArrays(XmlDocument doc) 
    { 
     // Arrearage 
     WrapElement(doc, "foo", "arrayItem", "http://url.com/namespace/foo"); 
    } 

    private static void WrapElement(XmlDocument doc, string elementName, string wrapperName, string nameSpace) 
    { 
     var names = new XmlNamespaceManager(doc.NameTable); 
     names.AddNamespace("a", nameSpace); 

     var Nodes = doc.SelectNodes("//a:" + elementName, names); 

     if (Nodes.Count > 0) 
     { 
      var newBorrower = doc.CreateElement(Nodes.Item(0).Prefix, wrapperName, Nodes.Item(0).NamespaceURI); 

      foreach (XmlElement node in Nodes) 
      { 
       newBorrower.AppendChild(node.Clone()); 
      } 

      Nodes.Item(0).ParentNode.ReplaceChild(newBorrower, Nodes.Item(0)); 

      for (int i = 1; i <= Nodes.Count - 1; i++) 
      { 
       Nodes.Item(i).ParentNode.RemoveChild(Nodes.Item(i)); 
      } 
     } 
    } 

    private static void WrapRenameElement(XmlDocument doc, string newName, string elementName, string wrapperName, string nameSpace, string newNamespace) 
    { 
     var names = new XmlNamespaceManager(doc.NameTable); 
     names.AddNamespace("a", nameSpace); 
     names.AddNamespace("b", newNamespace); 

     var Nodes = doc.SelectNodes("//a:" + elementName + "/..", names); 

     foreach (XmlElement parent in Nodes) 
     { 
      var newBorrower = doc.CreateElement(parent.Prefix, wrapperName, parent.NamespaceURI); 

      foreach (XmlElement child in parent.ChildNodes) 
      { 
       if (child.LocalName == elementName) 
       { 
        var newNode = RenameNode(child.Clone(), newNamespace, newName); 
        parent.RemoveChild(child); 
        newBorrower.AppendChild(newNode); 
       } 
      } 

      if (newBorrower.ChildNodes.Count > 0) 
       parent.AppendChild(newBorrower); 
     } 
    } 

    private static void WrapRenameElement(XmlDocument doc, string newName, string elementName, string wrapperName, string nameSpace) 
    { 
     var names = new XmlNamespaceManager(doc.NameTable); 
     names.AddNamespace("a", nameSpace); 

     var Nodes = doc.SelectNodes("//a:" + elementName + "/..", names); 

     foreach (XmlElement parent in Nodes) 
     { 
      var newBorrower = doc.CreateElement(parent.Prefix, wrapperName, parent.NamespaceURI); 

      foreach (XmlElement child in parent.ChildNodes) 
      { 
       if (child.LocalName == elementName) 
       { 
        var newNode = RenameNode(child.Clone(), nameSpace, newName); 
        parent.RemoveChild(child); 
        newBorrower.AppendChild(newNode); 
       } 
      } 

      if (newBorrower.ChildNodes.Count > 0) 
       parent.AppendChild(newBorrower); 
     } 
    } 

    public static XmlNode RenameNode(XmlNode node, string namespaceURI, string qualifiedName) 
    { 
     if (node.NodeType == XmlNodeType.Element) 
     { 
      XmlElement oldElement = (XmlElement)node; 
      XmlElement newElement = 
      node.OwnerDocument.CreateElement(qualifiedName, namespaceURI); 

      while (oldElement.HasAttributes) 
      { 
       newElement.SetAttributeNode(oldElement.RemoveAttributeNode(oldElement.Attributes[0])); 
      } 

      while (oldElement.HasChildNodes) 
      { 
       newElement.AppendChild(oldElement.FirstChild); 
      } 

      if (oldElement.ParentNode != null) 
      { 
       oldElement.ParentNode.ReplaceChild(newElement, oldElement); 
      } 

      return newElement; 
     } 
     else 
     { 
      return null; 
     } 
    } 
} 

は、それはかなりありません、それは基本的にハックですが、このソリューションは、私が持っていた問題のために動作します。私は誰もこれに対処してはいけないことを願っていますが、もしそうなら、これが助けてくれることを願っています。

+0

問題を説明してくれました。それを解決するために急いでください。 – RichardHowells

1

私はあなたが探しているものを理解している場合、属性を追加しよう:

[XmlElement("arrayItem")] 
public List<arrayItem> arrayItems {get; set;} 

はEDIT:

ok私はすぐに例を試してみましたが、ここでは私のために働いていたもの:

オブジェクト:

[DataContract] 
public class SomeObject 
{ 
    [DataMember(Order = 0)] 
    [XmlElement()] 
    public string item1 { get; set; } 

    [DataMember(Order = 1)] 
    [XmlElement()] 
    public string thing1 { get; set; } 

    [DataMember(Order = 2)] 
    [XmlElement("arrayItem")] 
    public List<arrayItem> arrayItems { get; set; } 

    public SomeObject() 
    { 
     arrayItems = new List<arrayItem>(); 
    } 
} 

[DataContract] 
public class arrayItem 
{ 
    [DataMember] 
    [XmlElement()] 
    public string foo { get; set; } 
} 

使用されるコード:

XmlSerializerNamespaces _namespaces = new XmlSerializerNamespaces(); 
_namespaces.Add(string.Empty, string.Empty); 
SomeObject sm = new SomeObject(); 
sm.arrayItems.Add(new arrayItem() { foo = "foo1" }); 
sm.arrayItems.Add(new arrayItem() { foo = "foo2" }); 
sm.item1 = "item1"; 
sm.thing1 = "thing1"; 
_xmlSerializer = new XmlSerializer(typeof(SomeObject)); 
//writer is XmlWriter which writes data to response stream 
_xmlSerializer.Serialize(writer, sm, _namespaces); 

結果:

<SomeObject> 
    <item1>item1</item1> 
    <thing1>thing1</thing1> 
    <arrayItem> 
    <foo>foo1</foo> 
    </arrayItem> 
    <arrayItem> 
    <foo>foo2</foo> 
    </arrayItem> 
</SomeObject> 
+0

申し訳ありません私の投稿の文言は悪いと思います。私はそれを変更しました。 にラップする出力を生成します。が存在しないようにする必要があります。 – ClaytonHunt

+0

私の答えを編集し、XmlElement属性を使用しようとしました – Reniuz

+0

まだコンテナ内に配列を出力します。私は問題は、DataContractとDataMember属性を使用しなければならないと思います。なぜなら、私はこれを正しく見えるようにすることができますが、SOAPメッセージの重要な部分が正しくないためです。 – ClaytonHunt

関連する問題