none
WCF Service Listening directly on Service Bus Subscription throws WCF Deserialization Errors when Receiving messages from a Java client.

    Question

  • 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 = "*"), ReceiveContextEnabledDataContractFormatServiceKnownType(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>

    • Edited by bogatiy Wednesday, January 4, 2012 2:53 PM added more info
    Wednesday, January 4, 2012 2:46 PM

Answers

  • So the solution I currently have follows ...

     

    The solution uses a custom binding, a MatchAllMessage (MAM) filter, and a custom web content type mapper class. I show the pertinent pieces below. Though it's using a customBinding  it may not need to, but I've not tested that yet and will update this thread if I can get it to work. Using a straight NetMessagingBinding makes it rather simple. The below code is working. I have a data contract defining a 'Record' which is not shown. I setup a project called TestAzureBrokeredMessageTransfer.
    The MAM filter:
        class MatchAllMessageFilterEndpointBehaviorExtensionElement : BehaviorExtensionElement
        {
            public override Type BehaviorType
            {
                get
                {
                    return typeof(MatchAllMessageFilterEndpointBehavior);
                }
            }
     
            protected override object CreateBehavior ()
            {
                return new MatchAllMessageFilterEndpointBehavior();
            }
        }
     
        class MatchAllMessageFilterEndpointBehavior : AttributeIEndpointBehavior
        {
            public void AddBindingParameters (ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters){}
     
            public void ApplyClientBehavior (ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime){}
     
            public void ApplyDispatchBehavior (ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
            {
                endpointDispatcher.AddressFilter = new System.ServiceModel.Dispatcher.MatchAllMessageFilter();
            }
     
            public void Validate (ServiceEndpoint endpoint){ }
        }
    The custom Web encoding:
        class XmlContentTypeMapper : System.ServiceModel.Channels.WebContentTypeMapper
        {
            public override System.ServiceModel.Channels.WebContentFormat GetMessageFormatForContentType (string contentType)
            {
                return System.ServiceModel.Channels.WebContentFormat.Xml;
            }
        }
    The endpointbehavior wireup of MAM filter:
     <endpointBehaviors>
            <behavior name="securityBehavior">
              <matchAllMessageFilter />
              <transportClientEndpointBehavior>
                <tokenProvider>
                  <sharedSecret issuerName="owner" issuerSecret="{removed}" />
                </tokenProvider>
              </transportClientEndpointBehavior>
            </behavior>
          </endpointBehaviors>
    It's associated behavior extension:
          <behaviorExtensions>
            <add name="matchAllMessageFilter" type="TestAzureBrokeredMessageTransfer.MatchAllMessageFilterEndpointBehaviorExtensionElement, TestAzureBrokeredMessageTransfer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
          </behaviorExtensions>
    The customBinding:
          <customBinding>
            <binding name="customMessagingBinding" closeTimeout="00:03:00"
              openTimeout="00:03:00" receiveTimeout="00:03:00" sendTimeout="00:03:00">
              <webMessageEncoding webContentTypeMapperType="TestAzureBrokeredMessageTransfer.XmlContentTypeMapper, TestAzureBrokeredMessageTransfer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
              <netMessagingTransport>
                <transportSettings batchFlushInterval="00:00:01" />
              </netMessagingTransport>
            </binding>
          </customBinding>
    The service definition:
    <service name="TestAzureBrokeredMessageTransfer.Service1">
            <endpoint address="sb://{removed}.servicebus.windows.net/yyy"
              name="GenericSubscriptionEndpoint"
              behaviorConfiguration="securityBehavior"
              binding="customBinding"
              bindingConfiguration="customMessagingBinding"
              contract="TestAzureBrokeredMessageTransfer.IService1"
              listenUri="sb://{removed}.servicebus.windows.net/yyy/subscriptions/xxx" />
          </service>
    The contract:
       [ServiceContract(Namespace = "http://www.tcnp3.com/schema/TCNOS/Integration")]  
        public interface IService1
        {
            [OperationContract(IsOneWay = true, Action = "*"), ReceiveContextEnabled]
            void MessageRouter(Message msg);
        }
    The contract implementation:
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
        public class Service1 : IService1
        {
            public void MessageRouter(Message msg)
            {
                try
                {
                    if (msg.Properties.ContainsKey(BrokeredMessageProperty.Name))
                    {
                        Record aRecord = msg.GetBody<Record>();
                        BrokeredMessage bMsg = (msg.Properties[BrokeredMessageProperty.Name] as BrokeredMessageProperty).Message;
                        bMsg.Abandon();
                    }
                }
                catch (CommunicationException ce)
                {
                }
                catch (Exception e)
                {
                }
            }
     
        }
    Hopefully that's everything.

    • Marked as answer by bogatiy Thursday, January 12, 2012 5:48 PM
    Thursday, January 12, 2012 5:48 PM

All replies

  • 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)

     

    Hi,

    As you’ve found out in the trace, NetMessagingBinding uses binary encoding instead of text encoding. So unless your Java client sends the message in the same binary format, you can’t use NetMessagingBinding to handle the message. I don’t know exactly is the binary format. But it looks like base64 encoding. So you can try to encode the message using base64 on the Java side. But note it is recommended to use the REST API (which is encapsulated by the BrokeredMessage class on .NET platforms) if you want to interoperate with non-.NET platforms. In standard WCF, NetMsmqBinding is not interoperable. Similarly, you can’t expect NetMessagingBinding to be interoperable. The REST API model is easier to use than WCF, and it supports Java client as well. So please use REST API. If you have to use the WCF model and want to support non-.NET client, use BasicHttpRelayBinding (which of course means you can’t use brokered message behavior).  

    I suggest you use Fiddler tool to grasp http request and view the message format, if you are not sure, please post the request message of Fiddler on forums.

    Hope it can help you.


    Please mark the replies as answers if they help or unmark if not. If you have any feedback about my replies, please contact msdnmg@microsoft.com Microsoft One Code Framework
    Thursday, January 5, 2012 5:49 AM
  • Thanks for your response.

    I'm not sure this is what's happening, because I can now generate the identical exception with a .Net client.

    Using a MessagingFactory and a SubscriptionClient, I'm able to read these (java client sent) messages from the queue and deserialize the body using this code:

     

    Modified Serializer Code:
    var serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(Record));
    var body = msg.GetBody<object>(serializer) as Record;

     

    However, if I use this code to deserialize the body, the identical exception is generated (The input source is not correctly formatted.)

    DEFAULT CODE: 
    var body = msg.GetBody<object>() as Record;

    So with that in mind, I created a .Net client to send up messages to the topic, to remove the Java client from the mix.

    var serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(Record));
    BrokeredMessage message = new BrokeredMessage("some data", serializer);
    myTopicClient.Send(message);

    I noticed it doesn't matter whether a 'Record' object or just 'string' data is used in the BrokeredMessage constructor, as it doesn't ever get that far to complain. So this helped narrow it down to the deserialization.

    Using the DEFAULT CODE generates the exception. Using the Modified Serializer Code works.

    So this essentially recreated the exception using only .Net components and no Java client.

    Of course it is possible the root causes of the Java client generated exception and the .Net client generated exception are different, though both generating the identical exception.

    Friday, January 6, 2012 5:48 PM
  • Yes, i think this situation may caused by data formatting issue, whether you use Java Client or .Net Client, you only need to ensure the sender and receiver format is the same, such as binary format, i am strong to suggest you use Fiddler 2 to grasp and check the request message, you can also check the request data with this tool. 
    Please mark the replies as answers if they help or unmark if not. If you have any feedback about my replies, please contact msdnmg@microsoft.com Microsoft One Code Framework
    • Proposed as answer by Arwind - MSFT Tuesday, January 10, 2012 2:11 AM
    Saturday, January 7, 2012 2:20 AM
  • So the solution I currently have follows ...

     

    The solution uses a custom binding, a MatchAllMessage (MAM) filter, and a custom web content type mapper class. I show the pertinent pieces below. Though it's using a customBinding  it may not need to, but I've not tested that yet and will update this thread if I can get it to work. Using a straight NetMessagingBinding makes it rather simple. The below code is working. I have a data contract defining a 'Record' which is not shown. I setup a project called TestAzureBrokeredMessageTransfer.
    The MAM filter:
        class MatchAllMessageFilterEndpointBehaviorExtensionElement : BehaviorExtensionElement
        {
            public override Type BehaviorType
            {
                get
                {
                    return typeof(MatchAllMessageFilterEndpointBehavior);
                }
            }
     
            protected override object CreateBehavior ()
            {
                return new MatchAllMessageFilterEndpointBehavior();
            }
        }
     
        class MatchAllMessageFilterEndpointBehavior : AttributeIEndpointBehavior
        {
            public void AddBindingParameters (ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters){}
     
            public void ApplyClientBehavior (ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime){}
     
            public void ApplyDispatchBehavior (ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
            {
                endpointDispatcher.AddressFilter = new System.ServiceModel.Dispatcher.MatchAllMessageFilter();
            }
     
            public void Validate (ServiceEndpoint endpoint){ }
        }
    The custom Web encoding:
        class XmlContentTypeMapper : System.ServiceModel.Channels.WebContentTypeMapper
        {
            public override System.ServiceModel.Channels.WebContentFormat GetMessageFormatForContentType (string contentType)
            {
                return System.ServiceModel.Channels.WebContentFormat.Xml;
            }
        }
    The endpointbehavior wireup of MAM filter:
     <endpointBehaviors>
            <behavior name="securityBehavior">
              <matchAllMessageFilter />
              <transportClientEndpointBehavior>
                <tokenProvider>
                  <sharedSecret issuerName="owner" issuerSecret="{removed}" />
                </tokenProvider>
              </transportClientEndpointBehavior>
            </behavior>
          </endpointBehaviors>
    It's associated behavior extension:
          <behaviorExtensions>
            <add name="matchAllMessageFilter" type="TestAzureBrokeredMessageTransfer.MatchAllMessageFilterEndpointBehaviorExtensionElement, TestAzureBrokeredMessageTransfer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
          </behaviorExtensions>
    The customBinding:
          <customBinding>
            <binding name="customMessagingBinding" closeTimeout="00:03:00"
              openTimeout="00:03:00" receiveTimeout="00:03:00" sendTimeout="00:03:00">
              <webMessageEncoding webContentTypeMapperType="TestAzureBrokeredMessageTransfer.XmlContentTypeMapper, TestAzureBrokeredMessageTransfer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
              <netMessagingTransport>
                <transportSettings batchFlushInterval="00:00:01" />
              </netMessagingTransport>
            </binding>
          </customBinding>
    The service definition:
    <service name="TestAzureBrokeredMessageTransfer.Service1">
            <endpoint address="sb://{removed}.servicebus.windows.net/yyy"
              name="GenericSubscriptionEndpoint"
              behaviorConfiguration="securityBehavior"
              binding="customBinding"
              bindingConfiguration="customMessagingBinding"
              contract="TestAzureBrokeredMessageTransfer.IService1"
              listenUri="sb://{removed}.servicebus.windows.net/yyy/subscriptions/xxx" />
          </service>
    The contract:
       [ServiceContract(Namespace = "http://www.tcnp3.com/schema/TCNOS/Integration")]  
        public interface IService1
        {
            [OperationContract(IsOneWay = true, Action = "*"), ReceiveContextEnabled]
            void MessageRouter(Message msg);
        }
    The contract implementation:
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
        public class Service1 : IService1
        {
            public void MessageRouter(Message msg)
            {
                try
                {
                    if (msg.Properties.ContainsKey(BrokeredMessageProperty.Name))
                    {
                        Record aRecord = msg.GetBody<Record>();
                        BrokeredMessage bMsg = (msg.Properties[BrokeredMessageProperty.Name] as BrokeredMessageProperty).Message;
                        bMsg.Abandon();
                    }
                }
                catch (CommunicationException ce)
                {
                }
                catch (Exception e)
                {
                }
            }
     
        }
    Hopefully that's everything.

    • Marked as answer by bogatiy Thursday, January 12, 2012 5:48 PM
    Thursday, January 12, 2012 5:48 PM
  • The MAM filter can be removed from the above by adding this attribute for the service implementation:

     

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, AddressFilterMode = AddressFilterMode.Any)]
        public class Service1 : IService1

    Thursday, January 12, 2012 9:38 PM
  • Without the AddressFilterMode.Any (which is the Match All Messages attribute), this is the exception, rather generic in nature, that is quenched:

     

    System.ServiceModel.FaultException: The message with To '' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher.  Check that the sender and receiver's EndpointAddresses agree.

       at System.ServiceModel.Dispatcher.ErrorBehavior.ThrowAndCatch(Exception e, Message message)

    Friday, January 13, 2012 4:20 PM