起因:
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序列化的行为呢?