WCF 在没有容器的情况下序列化数组或集合

Cla*_*unt 3 c# wcf serialization deserialization

我有一种情况,我们正在连接到 SOAP 服务。

我们得到的响应如下所示:

<SomeObject>
    <item1>1</item1>
    <thing1>2</thing1>
    <arrayItem><foo>text</foo></arrayItem>
    <arrayItem><foo>text1</foo></arrayItem>
    <arrayItem><foo>text2</foo></arrayItem>
</SomeObject>
Run Code Online (Sandbox Code Playgroud)

我需要复制该响应的输出。我一直遇到的问题是<arrayItem>'s 被封装了<arrayItemList>,我真的需要把's 去掉<arrayItemList>

有谁知道我可以在 WCF 对象上放什么来正确序列化/反序列化我们接收的对象?

编辑

我正在处理的对象是这样的:

[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;}
}
Run Code Online (Sandbox Code Playgroud)

Cla*_*unt 5

不幸的是,我无法找到一个很好的解决方案。但是,我确实找到了一个可行的解决方案。

警告 - 如果可能,您应该尝试修改 WSDL 以防止需要此解决方案。这更像是一个 hack 然后是一个建议的解决方案,但会在紧要关头工作。

解决方案是实现 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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

就像我说的,它并不漂亮,它本质上是一个 hack,但是这个解决方案可以解决我遇到的问题。我希望没有其他人需要处理这个问题,但如果他们这样做了,我希望这会有所帮助。