A Java-based client is using REST APIs to post messages to a Topic. This client has no knowledge of the WCF Service contract or how the messages are being consumed. This client posts a specific message (a 'Record' data structure conforming to an XML
schema) to the Topic.
A WCF service with endpoint listener on a Subscription to the Topic attempts to consume the messages, but throws a deserialization error, as follows:
System.Xml.XmlException: The input source is not correctly formatted.
at System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, String res, String arg1, String arg2, String arg3)
at System.Xml.XmlExceptionHelper.ThrowInvalidBinaryFormat(XmlDictionaryReader reader)
at System.Xml.XmlBinaryReader.ReadNode()
at System.Xml.XmlBaseReader.MoveToContent()
at System.ServiceModel.Channels.StreamedMessage..ctor(XmlDictionaryReader reader, Int32 maxSizeOfHeaders, MessageVersion desiredVersion)
at System.ServiceModel.Channels.Message.CreateMessage(XmlDictionaryReader envelopeReader, Int32 maxSizeOfHeaders, MessageVersion version)
at System.ServiceModel.Channels.BinaryMessageEncoderFactory.BinaryMessageEncoder.ReadMessage(Stream stream, Int32 maxSizeOfHeaders, String contentType)
at Microsoft.ServiceBus.Messaging.Channels.ServiceBusInputChannelBase`1.ConvertToWcfMessage(BrokeredMessage brokeredMessage)
at Microsoft.ServiceBus.Messaging.Channels.ServiceBusInputChannelBase`1.System.ServiceModel.Channels.IInputChannel.EndTryReceive(IAsyncResult result, Message& wcfMessage)
at System.ServiceModel.Dispatcher.InputChannelBinder.EndTryReceive(IAsyncResult result, RequestContext& requestContext)
at System.ServiceModel.Dispatcher.ErrorHandlingReceiver.EndTryReceive(IAsyncResult result, RequestContext& requestContext)
When we use a Channel Factory to post messages, of course all works fine. But the channel client has knowledge of the WCF contract and thus the data structure in the body of the message is different as it contains the name of the function being called.
The Java client posts and object that can be deserialized when using a channel factory client to consume messages from the Subscription.
WCF Tracing shows only the encoded message in the body of the soap message:
<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.microsoft.com/netservices/2011/06/servicebus/SbmpMessageReceiver/TryReceiveResponse</a:Action>
<a:RelatesTo>urn:uuid:c15d5167-0aeb-452f-97d8-2be814bc9f37</a:RelatesTo>
<a:To s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/anonymous</a:To>
<ActivityId CorrelationId="67e2c5eb-e190-4f66-9cab-60b51cce3c74" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">00000000-0000-0000-0000-000000000000</ActivityId>
</s:Header>
<s:Body>
<TryReceiveResponse xmlns="http://schemas.microsoft.com/netservices/2011/06/servicebus" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<TryReceiveResult>true</TryReceiveResult>
<messages xmlns:b="http://schemas.datacontract.org/2004/07/Microsoft.ApplicationServer.Messaging">
<b:Message>
<Message>AQAAAAAABgABIAA4NTVlYTJjZTYwN2M0MmIyOTgyZmM5MTg4MTRiOWU5ZgUIAChDHOviNgpDFAgAM9b5mk6YzkgVCACEAAAAAAAAABgEAAEAAAAICgBwbGFpbi90ZXh0HgUABABUeXBlDwQAQ2FsbAgAUGFzc3dvcmQPrABHaFczVHFyTVZENzNiUm5qOE1qTG1MbW9WOU5TK3pvQW10QklEN25ySE5melVaVXJpb2k2dGJqZjdla2tUbWRuZ1FxaFBnakUrUUE4YlNNcFgyVnpzT0V2UUpNZUQ1aFR1SFZQUkZWczRDa1BNVVp3TVFmUExJQkZzVit4U0hUb3VMMVF5ZFlrQWFYb2ZQeXgvWnNOV1psUTAzWHJnUnV4UXo5SXIwQ3NsSXc9CABVc2VybmFtZQ+sAGt5VUh6OUhDblFvN3pnZE4rdXcvYWVpN0R2WFEzaTkwM3BqRGwxWU9wc1E5WFBVOUpNQnNRdHJhdFRCR3p2dUtBa1BWU2pHWnV2RnUwc1VqWGlNR3BQaEVVWVZuS1hhcFFFcTV2NUh4Wk02dE9IeGdrbnZJTW9JV3p5ZjN6V0VKVTVhaWw1bHo3US82TUpKbmVXSU1PdldyZnZOQTdpVUQvcVJubWFza0ltND0LAENhbXBhaWduS2V5DwQANTU2NRIAQ2xpZW50QWRkcmVzc0FsaWFzDwEAMR+4CQAAAAAAADw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+PFJlY29yZCB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxucz0iaHR0cDovL3d3dy50Y25wMy5jb20vc2NoZW1hL1RDTk9TL0ludGVncmF0aW9uIj48UmVjb3JkSW5mbz48UmVjb3JkRGF0YT48UmVjb3JkRGF0YSAvPjwvUmVjb3JkRGF0YT48UmVzdWx0RGF0YT48UmVzdWx0RGF0YT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PlJlc3VsdDwvRGF0YUtleT48RGF0YVZhbHVlPjUwMDA8L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PlRDTkRpYWxlZE51bWJlcjwvRGF0YUtleT48RGF0YVZhbHVlPjc2NTc1MTc0NTE8L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PlJlY29yZGluZ0xpbms8L0RhdGFLZXk+PERhdGFWYWx1ZT5odHRwczovL3MzLmFtYXpvbmF3cy5jb20vSm9uc0NodWNrL0luZG9jdHJpbmF0aW9uLm1wMzwvRGF0YVZhbHVlPjwvRGF0YVBhaXJUeXBlPjxEYXRhUGFpclR5cGU+PERhdGFLZXk+RGlhbGVkTnVtYmVyRmllbGQ8L0RhdGFLZXk+PERhdGFWYWx1ZT5XT1JLUEg8L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PkFnZW50SUQ8L0RhdGFLZXk+PERhdGFWYWx1ZT5KUlM8L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PlRvdGFsTGVuZ3RoPC9EYXRhS2V5PjxEYXRhVmFsdWU+MTU8L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PlBvb2xJRDwvRGF0YUtleT48RGF0YVZhbHVlPjc8L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PkRyaXZlTGlzdDwvRGF0YUtleT48RGF0YVZhbHVlPkIsQzwvRGF0YVZhbHVlPjwvRGF0YVBhaXJUeXBlPjxEYXRhUGFpclR5cGU+PERhdGFLZXk+U3RvcmFnZVBhdGg8L0RhdGFLZXk+PERhdGFWYWx1ZT5SRUNPUkRJTkdTPC9EYXRhVmFsdWU+PC9EYXRhUGFpclR5cGU+PERhdGFQYWlyVHlwZT48RGF0YUtleT5SZWNvcmRpbmdTdGFydFRpbWU8L0RhdGFLZXk+PERhdGFWYWx1ZT4xOjQxPC9EYXRhVmFsdWU+PC9EYXRhUGFpclR5cGU+PERhdGFQYWlyVHlwZT48RGF0YUtleT5SZWNvcmRpbmdFbmRUaW1lPC9EYXRhS2V5PjxEYXRhVmFsdWU+MjI6MDU8L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PlJlY29yZGluZ0RheXM8L0RhdGFLZXk+PERhdGFWYWx1ZT5NT046VFVFOldFRDpUSFU6U0FUPC9EYXRhVmFsdWU+PC9EYXRhUGFpclR5cGU+PERhdGFQYWlyVHlwZT48RGF0YUtleT5QdXJnZURhdGU8L0RhdGFLZXk+PERhdGFWYWx1ZT4xMi8xMS8xMTwvRGF0YVZhbHVlPjwvRGF0YVBhaXJUeXBlPjxEYXRhUGFpclR5cGU+PERhdGFLZXk+RGF0ZTwvRGF0YUtleT48RGF0YVZhbHVlPjEyLzMwLzIwMTE8L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PlRpbWU8L0RhdGFLZXk+PERhdGFWYWx1ZT4xNDoyNzoxMzwvRGF0YVZhbHVlPjwvRGF0YVBhaXJUeXBlPjwvUmVzdWx0RGF0YT48L1Jlc3VsdERhdGE+PE1lc3NhZ2U+PE1lc3NhZ2U+PERhdGFQYWlyVHlwZT48RGF0YUtleT5Vc2VybmFtZTwvRGF0YUtleT48RGF0YVZhbHVlPk81NWhJN2NFVnk1bHg5cHJtOXd6enp4QnRPZXB5U2dONmd5c1hhOHFpNmtpc3NhVEYvRnpFTlVhN2N3WExwcjNjUC9XOTFnODh4TmJJVlR5eTErRDduTTdKTGg0UC9nN2ZzQUxMRDhNenpKMFUrOSthQkxJY0k4N2dEMThWRU1oWEhXUGxVczYrNlhYQXVFenFIVUN5NWpvWXJIWXZlQVhpazlBZFQ4cmJDQT08L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48RGF0YVBhaXJUeXBlPjxEYXRhS2V5PlBhc3N3b3JkPC9EYXRhS2V5PjxEYXRhVmFsdWU+RCtoZXRReVVnc3VsbDNtM2tLVW9IUTZwM1JGZlVOQWpSVld5eVRXek8rV2VPWjc0azVsVm9Xemt4RU10bGVOTWJSVERBQzlXWGpqa3FYS2l3K3ZGOWc2REp0Mk93dFFUaVE0Z29JRTBmN3dxVHRQRUlaMjRaUkYxQXA3VWlFNy9Xdml1MjJNWXNjVWJVT2ZST2NPZkF3VGJzVktyVWtqbUlVcXdPa3NrRDVRPTwvRGF0YVZhbHVlPjwvRGF0YVBhaXJUeXBlPjxEYXRhUGFpclR5cGU+PERhdGFLZXk+Q2xpZW50QWRkcmVzc0FsaWFzPC9EYXRhS2V5PjxEYXRhVmFsdWU+MTwvRGF0YVZhbHVlPjwvRGF0YVBhaXJUeXBlPjxEYXRhUGFpclR5cGU+PERhdGFLZXk+QWNjb3VudDwvRGF0YUtleT48RGF0YVZhbHVlPjEyMzwvRGF0YVZhbHVlPjwvRGF0YVBhaXJUeXBlPjxEYXRhUGFpclR5cGU+PERhdGFLZXk+Q2FtcGFpZ25LZXk8L0RhdGFLZXk+PERhdGFWYWx1ZT4xMjM8L0RhdGFWYWx1ZT48L0RhdGFQYWlyVHlwZT48L01lc3NhZ2U+PC9NZXNzYWdlPjwvUmVjb3JkSW5mbz48L1JlY29yZD4=</Message>
</b:Message>
</messages>
</TryReceiveResponse>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
Because the Java client has no knowledge of the WCF Service contract, the body of the message just contains a 'Record' object. Using a channel factory and a subscription client, the BrokeredMessages can be dequeued from the Subscription and successfully
deserialized by using this code:
var serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(Record));
BrokeredMessage msg = mySubClient.Receive(new TimeSpan(0, 0, 10));
Record aRecord = msg.GetBody<Record>(serializer);
On the WCF service, the function which should recieve and process the messages has these attributes and function signature:
[OperationContract(IsOneWay = true, Action = "*"), ReceiveContextEnabled]
void UpdateAccount (Record record);
The exception leads to believe the NetMessagingBinding is using the XMLSerializer to deserialize rather than the DataContractSerializer, which is the WCF default serializer. We've experimented using attributes such as the following:
[OperationContract(IsOneWay = true, Action = "*"), ReceiveContextEnabled, DataContractFormat, ServiceKnownType(typeof(Record))]
void UpdateAccount (Record myRecord);
This has no effect, and putting it the attributes onto the Service class rather than the function also has no effect.
So, in summary, a BrokeredMessage is posted to a Topic. A WCF service with endpoint listening on a subscription throws a deserialization error.
Separately, a stand-alone client using a Channel Factory can receive and deserialize the message.
The issue is how to troubleshoot the deserialization error with WCF (all tracing is turned up to verbose and all messages are logged).
Messages from a ChannelFactory client posting messages to the Topic will post something like (there's a lot more there in a real one like namespace attributes, this is just to explain the difference):
<UpdateAccount>
<Record>
... data ...
</Record>
</UpdateAccount>
While the Java client posts a message with something like this, as it has no knowledge of the WCF contract:
<Record>
... data ...
</Record>