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

问题描述 投票:0回答:3

我遇到了一种情况,我们正在连接到 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 对象上放置什么来正确序列化/反序列化我们收到的对象?

编辑

我正在使用的对象是这样的:

[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;}
}
c# wcf serialization deserialization
3个回答
5
投票

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

警告 - 如果可能的话,您应该尝试修改 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
投票

如果我明白你在寻找什么,请尝试添加属性:

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

0
投票

正在使用什么版本的.net框架?我目前面临类似的问题,我必须创建一个可以接收具有类似结构的请求的wcf

© www.soinside.com 2019 - 2024. All rights reserved.