.NET WCF serialization issues
The situation: system A is supposed to expose SOAP 1.2 web service for system B to call. In order for A to know what the message looks like, B sent an XSD to A describing the contents of the message. A generated the stubs using the .NET xsd.exe tool, created the simple webservice around this and the job was done.
However; when B calls this webservice, A refuses to serialize the SOAP/XML content to the generated proxy class instances. I realize this must be down to the way the serialization is defined on the webservice side on system A, but have been unable to locate exactly what is going wrong.
What the message from B looks like (anonymized) - FAILS:
<ns2:Set_Out xmlns:ns2="http://a.a/1.0" xmlns:ns1="http://b.b/1.0" xmlns:ns0="http://c.c">
<Context xmlns="">
<Foo>test</Foo>
<Bar>test</Bar>
...
</Context>
What a test message from a test client (based on the WSDL) looks like - WORKS:
<Set_Out xmlns="http://a.a/1.0">
<Context xmlns:b="http://schemas.datacontract.org/2004/07/x.x" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<b:Foo>TEST</b:Foo>
<b:Bar>test</b:Bar>
...
</Context>
When the webservice built by A receives the messages from B, it doesn't serialize the开发者_如何转开发 message at all. The objects of the proxy (for instance Context
) are null
. When it receives the messages from a test client, everything is generated correctly.
The serialization attributes on the proxy:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://a.a/1.0")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://a.a/1.0", IsNullable=false)]
[System.ServiceModel.MessageContract]
public partial class Set_Out {
[System.Xml.Serialization.XmlElementAttribute(Namespace="http://a.a/1.0", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] [System.ServiceModel.MessageBodyMember(Order=0)]
public ContextType Context;
...
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://a.a/1.0")]
public partial class ContextType {
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string Foo;
Things I find odd:
- When generating the WSDL for this service, the WSDL adds its own namespaces to the WSDL definition (
xmlns:b
in the example above, for instance). - The WSDL doesn't respect the
unqualified
annotations defined in the proxy, and makes everything qualified.
I've tried various combinations of annotations, but nothing seems to help; the messages from B aren't correctly deserialized to the proxies generated by A. Any ideas/pointers/help would be much appreciated!
In a typical case of "ask the question, solve it yourself 5 minutes later" I've managed to solve my problem.
The issue was that, apparently, when using WCF .NET uses a default serializer for the classes involved in the data contract. This default serializer (I believe it's DataContractSerializer
) apparently doesn't really allow much in the way of configuration. I had to tell WCF to use XmlSerializer
to serialize the message. To do this, I had to add the [XmlSerializerFormat()]
annotation to the service contract interface (apparently it's meant to work on operations as well). Example:
[ServiceContract(Namespace = "http://a.a/1.0")]
[XmlSerializerFormat()]
public interface IMyWebService
{
[OperationContract()]
void DoStuff(Set_Out message);
}
After adding the [XmlSerializerFormat()]
annotation, the WSDL changed significantly (proper namespaces) and the messages are serialized correctly.
Forum post that set me on the right track: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/c7fede29-56c2-4ff3-bd02-48e3e0b2cec1/
(this is actually a comment, but it can't fit)
Try adding the system.diagnostics to your web.config to find out more information about errors:
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="sdt"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "C:\MyLog.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
You can view the svclog using C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcTraceViewer.exe
(or similar). Add this to both services (different log filenames of course), and see which one fails, and exactly why.
I would suspect that the serialization is OK, but some binding/setting of the service causes the call to fail.
精彩评论