我有一种情况,我们正在连接到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;}
}
答案 0 :(得分: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;
}
}
}
就像我说的那样,它并不漂亮,而且它本质上是一个黑客攻击,但这个解决方案可以解决我遇到的问题。我希望没有其他人能够解决这个问题,但如果他们这样做,我希望这会有所帮助。
答案 1 :(得分: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>