起因:
WCF序列化的对象Delphi可以正确的接收,但是Delphi序列化的对象WCF端接收就会因反序列化错误,导致接收到的对象为NULL。
还未找到解决办法,现在用的是传递XML字符串的方法而不是直接序列化对象的方式来暂时解决这个问题。但是这样就会很繁琐,毕竟要拼凑XML是一件挺繁琐的事情。
下面两段式用tcp trace抓到的soap
C#: <MessageLogTraceRecord> <HttpRequest xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace"> <Method>POST</Method> <QueryString></QueryString> <WebHeaders> <Connection>Keep-Alive</Connection> <Content-Length>385</Content-Length> <Content-Type>text/xml; charset=utf-8</Content-Type> <Expect>100-continue</Expect> <Host>pc-201007021201:8099</Host> <VsDebuggerCausalityData>uIDPozhfWXopshZDtHDngP/FfEwAAAAABlnI7S7LLE+3UhFI/NQahmUvtiY6tpBBkfIU7zTLAMsACQAA</VsDebuggerCausalityData> <SOAPAction>"http://tempuri.org/IService1/GetDataUsingDataContract"</SOAPAction> </WebHeaders> </HttpRequest> <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://pc-201007021201:8099/wcf/WcfServiceLibrary1.Service1.svc</To> <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService1/GetDataUsingDataContract</Action> </s:Header> <s:Body> <GetDataUsingDataContract xmlns="http://tempuri.org/"> <composite xmlns:a="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <a:BoolValue>true</a:BoolValue> <a:StringValue>test</a:StringValue> </composite> </GetDataUsingDataContract> </s:Body> </s:Envelope> </MessageLogTraceRecord>
Delphi: <MessageLogTraceRecord> <HttpRequest xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace"> <Method>POST</Method> <QueryString></QueryString> <WebHeaders> <Cache-Control>no-cache</Cache-Control> <Connection>Keep-Alive</Connection> <Content-Length>482</Content-Length> <Content-Type>text/xml</Content-Type> <Host>pc-201007021201:8099</Host> <User-Agent>Borland SOAP 1.2</User-Agent> <SOAPAction>"http://tempuri.org/IService1/GetDataUsingDataContract"</SOAPAction> </WebHeaders> </HttpRequest> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://pc-201007021201:8099/wcf/WcfServiceLibrary1.Service1.svc</To> <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService1/GetDataUsingDataContract</Action> </s:Header> <SOAP-ENV:Body> <GetDataUsingDataContract xmlns="http://tempuri.org/"> <composite xmlns="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1"> <BoolValue>true</BoolValue> <StringValue>test</StringValue> </composite> </GetDataUsingDataContract> </SOAP-ENV:Body> </SOAP-ENV:Envelope> </MessageLogTraceRecord>
我原以为因为C#中定义了2个“有名称命名空间,分别是a和i”,所以需要名称来区别命名空间。而Delphi中定义的是“无名称命名空间”,所以不要前缀才是正确的,没有前缀的都属于"无名称命名空间"。 现在不知道问题出在哪了,难道是 <User-Agent>Borland SOAP 1.2</User-Agent> 指定了是1.2,但是里面用的命名空间又是1.1的,所以冲突?(后面证实是错误的理解)
SOAP 1.2 uses "http://www.w3.org/2003/05/soap-envelope" SOAP 1.1 uses "http://schemas.xmlsoap.org/soap/envelope/"
最后察觉问题所在:
还是命名空间冲突的问题 <composite xmlns:a="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <a:BoolValue>true</a:BoolValue> <a:StringValue>test</a:StringValue> </composite>
在上面所示的这种情况下,composite这个元素的命名空间仍然是为空的,也就是说.NET这边要求就是composite这个元素命名空间为空
测试代码如下,因为WCF默认调用的是DataContractSerializer
static void Serialize<T>(string filePath,object graph) { DataContractSerializer serializer = new DataContractSerializer(typeof(T));
using (XmlWriter writer = new XmlTextWriter(filePath, Encoding.UTF8)) { serializer.WriteObject(writer, graph); }
}
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/WcfServiceLibrary1")] public class CompositeType { bool boolValue = true; string stringValue = "Hello ";
[DataMember] public bool BoolValue { get { return boolValue; } set { boolValue = value; } }
[DataMember] public string StringValue { get { return stringValue; } set { stringValue = value; } } }
我自己给CompositeType添加上了命名空间前缀,反序列化成功
<a:CompositeType xmlns:a="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1"> <a:BoolValue>true</a:BoolValue> <a:StringValue>test</a:StringValue> </a:CompositeType>
所以说反序列化丢失了相应的值,这样的话就会OK
<composite xmlns:a="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <a:BoolValue>true</a:BoolValue> <a:StringValue>test</a:StringValue>
<BoolValue>true<BoolValue> <StringValue>test<StringValue> </composite>
或者这样
<a:CompositeType xmlns:a="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1"> <a:BoolValue>true</a:BoolValue> <a:StringValue>test</a:StringValue> </a:CompositeType>
问题结症找到了,但是解决方案只有把命名空间设置为空才行。很奇怪为什么会莫名其妙有个a:的前缀导致命名空间错误。我如何调整WCF序列化的行为呢?
|
请发表评论