Серийный массив или коллекция WCF без контейнера - PullRequest
3 голосов
/ 13 марта 2012

У меня есть ситуация, когда мы подключаемся к SOAP-сервису.

Ответ, который мы получаем, выглядит примерно так:

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

Мне нужно повторить вывод этого ответа.Проблема, с которой я постоянно сталкиваюсь, заключается в том, что <arrayItem> инкапсулированы <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;}
}

Ответы [ 2 ]

4 голосов
/ 08 мая 2012

К сожалению, я не смог найти отличное решение для этого. Я, однако, нашел работоспособное решение.

Предупреждение. Если это возможно, попытайтесь изменить 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;
        }
    }
}

Как я уже сказал, это не красиво и по сути взломано, но это решение подойдет для моей проблемы. Я надеюсь, что никто не должен иметь дело с этим, но если они это сделают, я надеюсь, что это поможет.

1 голос
/ 13 марта 2012

Если я понял, что вы ищете, попробуйте добавить атрибут:

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

РЕДАКТИРОВАТЬ:

хорошо, я быстро попробовал пример, и вот что работает для меня:

Объекты:

 [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>
...