.NET Framework Developer Center > .NET Development Forums > Windows Communication Foundation > Can you overriding Content type mismatch and get the message anyway?
Ask a questionAsk a question
 

AnswerCan you overriding Content type mismatch and get the message anyway?

  • Tuesday, September 01, 2009 6:25 PMeSchlosser Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I am writing a WCF  app that talks through the WSD scan proticals to a scanner. The problem I am running into is that WCF request/response messages must be the same Content type.

    In the WSD Scan RetrieveImage messages the request must be application/soap+xml; charset=utf-8 but the response coming from the scanner is a multipart/related message with MTOM embedded (the image). I get the Content type mismatch in my catch block.

    The error message goes on to say that if using a custom encoder to check that the IsContentTypeSupported method is implemented correctly. I am not using a custom message encoder.

    Is there a way to override this without a custom encoder? can you override the HandleReturnMessage method to do all the work yourself? Am I missing an easy solution?

    I must get this working.

    Thanks in advance for any help,

    Eric
    E Schlosser

Answers

  • Tuesday, September 01, 2009 9:39 PMCarlos FigueiraMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    I think the custom encoder is your only solution here. You need the outgoing messages to be application/soap+xml (what the TextMessageEncoder generates), but the incoming messages are multipart/related (what the MtomMessageEncoder understands). Your custom encoder would wrap one of each; on the WriteMessage method, it would use the text encoder, while on ReadMessage it would use the Mtom encoder.

        public class Post_480f1bc4_1fc4_40e9_a2ed_efcf3009d6ef
        {
            [ServiceContract]
            public interface ITest
            {
                [OperationContract]
                string Echo(string text);
            }
            public class Service : ITest
            {
                public string Echo(string text)
                {
                    return text;
                }
            }
            public class MyNewEncodingBindingElement : MessageEncodingBindingElement
            {
                MessageVersion messageVersion = MessageVersion.Default;
                public override MessageEncoderFactory CreateMessageEncoderFactory()
                {
                    return new MyNewEncoderFactory(this.messageVersion);
                }
                public override MessageVersion MessageVersion
                {
                    get
                    {
                        return this.messageVersion;
                    }
                    set
                    {
                        this.messageVersion = value;
                    }
                }
                public override BindingElement Clone()
                {
                    return this;
                }
                public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
                {
                    context.BindingParameters.Add(this);
                    return context.BuildInnerChannelFactory<TChannel>();
                }
                public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
                {
                    context.BindingParameters.Add(this);
                    return context.BuildInnerChannelListener<TChannel>();
                }
                public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
                {
                    return context.CanBuildInnerChannelFactory<TChannel>();
                }
                public override bool CanBuildChannelListener<TChannel>(BindingContext context)
                {
                    return context.CanBuildInnerChannelListener<TChannel>();
                }
            }
            class MyNewEncoderFactory : MessageEncoderFactory
            {
                MessageVersion messageVersion;
                MyNewEncoder encoder;
                public MyNewEncoderFactory(MessageVersion messageVersion)
                {
                    this.messageVersion = messageVersion;
                    this.encoder = new MyNewEncoder(messageVersion);
                }
                public override MessageEncoder Encoder
                {
                    get { return this.encoder; }
                }
                public override MessageVersion MessageVersion
                {
                    get { return this.encoder.MessageVersion; }
                }
            }
            class MyNewEncoder : MessageEncoder
            {
                MessageEncoder textEncoder;
                MessageEncoder mtomEncoder;
                public MyNewEncoder(MessageVersion messageVersion)
                {
                    this.textEncoder = new TextMessageEncodingBindingElement(messageVersion, Encoding.UTF8).CreateMessageEncoderFactory().Encoder;
                    this.mtomEncoder = new MtomMessageEncodingBindingElement(messageVersion, Encoding.UTF8).CreateMessageEncoderFactory().Encoder;
                }
                public override string ContentType
                {
                    get { return this.textEncoder.ContentType; }
                }
                public override string MediaType
                {
                    get { return this.textEncoder.MediaType; }
                }
                public override MessageVersion MessageVersion
                {
                    get { return this.textEncoder.MessageVersion; }
                }
                public override bool IsContentTypeSupported(string contentType)
                {
                    return this.mtomEncoder.IsContentTypeSupported(contentType);
                }
                public override T GetProperty<T>()
                {
                    T result = this.textEncoder.GetProperty<T>();
                    if (result == null)
                    {
                        result = this.mtomEncoder.GetProperty<T>();
                    }
    
                    if (result == null)
                    {
                        result = base.GetProperty<T>();
                    }
    
                    return result;
                }
                public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
                {
                    return this.mtomEncoder.ReadMessage(buffer, bufferManager, contentType);
                }
                public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
                {
                    return this.mtomEncoder.ReadMessage(stream, maxSizeOfHeaders, contentType);
                }
                public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
                {
                    return this.textEncoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
                }
                public override void WriteMessage(Message message, Stream stream)
                {
                    this.textEncoder.WriteMessage(message, stream);
                }
            }
            static Binding GetBinding(bool useCustomEncoder)
            {
                if (useCustomEncoder)
                {
                    return new CustomBinding(
                        new MyNewEncodingBindingElement(),
                        new HttpTransportBindingElement());
                }
                else
                {
                    return new CustomBinding(
                        new MtomMessageEncodingBindingElement(),
                        new HttpTransportBindingElement());
                }
            }
            public static void Test()
            {
                string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                host.AddServiceEndpoint(typeof(ITest), GetBinding(false), "");
                host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
                host.Open();
                Console.WriteLine("Host opened");
    
                ChannelFactory<ITest> factory = new ChannelFactory<ITest>(GetBinding(true), new EndpointAddress(baseAddress));
                ITest proxy = factory.CreateChannel();
                Console.WriteLine(proxy.Echo("Hello"));
    
                ((IClientChannel)proxy).Close();
                factory.Close();
    
                Console.Write("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
        }
    
    
  • Thursday, September 24, 2009 6:21 PMeSchlosser Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Carlos,everyone, This last issue turned out it was a FW defect from the scanner, not creating the mime boundry delimiter correctly. As for the rest of the code, I had to change the ReadQuota.MaxArrayLength = int.MaxValue. Added it right below the MaxBufferSize change (see above) and now everything works Great! Thank you Carlos! Eric
    E Schlosser
    • Marked As Answer byeSchlosser Thursday, September 24, 2009 6:21 PM
    •  

All Replies

  • Tuesday, September 01, 2009 9:39 PMCarlos FigueiraMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    I think the custom encoder is your only solution here. You need the outgoing messages to be application/soap+xml (what the TextMessageEncoder generates), but the incoming messages are multipart/related (what the MtomMessageEncoder understands). Your custom encoder would wrap one of each; on the WriteMessage method, it would use the text encoder, while on ReadMessage it would use the Mtom encoder.

        public class Post_480f1bc4_1fc4_40e9_a2ed_efcf3009d6ef
        {
            [ServiceContract]
            public interface ITest
            {
                [OperationContract]
                string Echo(string text);
            }
            public class Service : ITest
            {
                public string Echo(string text)
                {
                    return text;
                }
            }
            public class MyNewEncodingBindingElement : MessageEncodingBindingElement
            {
                MessageVersion messageVersion = MessageVersion.Default;
                public override MessageEncoderFactory CreateMessageEncoderFactory()
                {
                    return new MyNewEncoderFactory(this.messageVersion);
                }
                public override MessageVersion MessageVersion
                {
                    get
                    {
                        return this.messageVersion;
                    }
                    set
                    {
                        this.messageVersion = value;
                    }
                }
                public override BindingElement Clone()
                {
                    return this;
                }
                public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
                {
                    context.BindingParameters.Add(this);
                    return context.BuildInnerChannelFactory<TChannel>();
                }
                public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
                {
                    context.BindingParameters.Add(this);
                    return context.BuildInnerChannelListener<TChannel>();
                }
                public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
                {
                    return context.CanBuildInnerChannelFactory<TChannel>();
                }
                public override bool CanBuildChannelListener<TChannel>(BindingContext context)
                {
                    return context.CanBuildInnerChannelListener<TChannel>();
                }
            }
            class MyNewEncoderFactory : MessageEncoderFactory
            {
                MessageVersion messageVersion;
                MyNewEncoder encoder;
                public MyNewEncoderFactory(MessageVersion messageVersion)
                {
                    this.messageVersion = messageVersion;
                    this.encoder = new MyNewEncoder(messageVersion);
                }
                public override MessageEncoder Encoder
                {
                    get { return this.encoder; }
                }
                public override MessageVersion MessageVersion
                {
                    get { return this.encoder.MessageVersion; }
                }
            }
            class MyNewEncoder : MessageEncoder
            {
                MessageEncoder textEncoder;
                MessageEncoder mtomEncoder;
                public MyNewEncoder(MessageVersion messageVersion)
                {
                    this.textEncoder = new TextMessageEncodingBindingElement(messageVersion, Encoding.UTF8).CreateMessageEncoderFactory().Encoder;
                    this.mtomEncoder = new MtomMessageEncodingBindingElement(messageVersion, Encoding.UTF8).CreateMessageEncoderFactory().Encoder;
                }
                public override string ContentType
                {
                    get { return this.textEncoder.ContentType; }
                }
                public override string MediaType
                {
                    get { return this.textEncoder.MediaType; }
                }
                public override MessageVersion MessageVersion
                {
                    get { return this.textEncoder.MessageVersion; }
                }
                public override bool IsContentTypeSupported(string contentType)
                {
                    return this.mtomEncoder.IsContentTypeSupported(contentType);
                }
                public override T GetProperty<T>()
                {
                    T result = this.textEncoder.GetProperty<T>();
                    if (result == null)
                    {
                        result = this.mtomEncoder.GetProperty<T>();
                    }
    
                    if (result == null)
                    {
                        result = base.GetProperty<T>();
                    }
    
                    return result;
                }
                public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
                {
                    return this.mtomEncoder.ReadMessage(buffer, bufferManager, contentType);
                }
                public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
                {
                    return this.mtomEncoder.ReadMessage(stream, maxSizeOfHeaders, contentType);
                }
                public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
                {
                    return this.textEncoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
                }
                public override void WriteMessage(Message message, Stream stream)
                {
                    this.textEncoder.WriteMessage(message, stream);
                }
            }
            static Binding GetBinding(bool useCustomEncoder)
            {
                if (useCustomEncoder)
                {
                    return new CustomBinding(
                        new MyNewEncodingBindingElement(),
                        new HttpTransportBindingElement());
                }
                else
                {
                    return new CustomBinding(
                        new MtomMessageEncodingBindingElement(),
                        new HttpTransportBindingElement());
                }
            }
            public static void Test()
            {
                string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                host.AddServiceEndpoint(typeof(ITest), GetBinding(false), "");
                host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
                host.Open();
                Console.WriteLine("Host opened");
    
                ChannelFactory<ITest> factory = new ChannelFactory<ITest>(GetBinding(true), new EndpointAddress(baseAddress));
                ITest proxy = factory.CreateChannel();
                Console.WriteLine(proxy.Echo("Hello"));
    
                ((IClientChannel)proxy).Close();
                factory.Close();
    
                Console.Write("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
        }
    
    
  • Thursday, September 03, 2009 11:05 PMeSchlosser Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Carlos,

    Thank you!. I will plug this in and let you know.

     

    Eric


    E Schlosser
  • Wednesday, September 09, 2009 6:30 PMeSchlosser Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Carlos,

    I have got this working up to the point that I am recieveing mtom data back from the scanner. I then recieve an error stating that "The Maximum message quota for the incoming messages (65536) has been exceeded."

    Since this code build the custom binding on the fly, I can't find a place to set the MaxRecievedMessageSize property.

    Any help would be greatly appriciated.

    Eric


    E Schlosser
  • Wednesday, September 09, 2009 6:35 PMCarlos FigueiraMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code

    You can set it on the HttpTransportBindingElement:

            static Binding GetBinding(bool useCustomEncoder)
            {
                if (useCustomEncoder)
                {
                    return new CustomBinding(
                        new MyNewEncodingBindingElement(),
                        new HttpTransportBindingElement { MaxReceivedMessageSize = int.MaxValue });
                }
                else
                {
                    return new CustomBinding(
                        new MtomMessageEncodingBindingElement(),
                        new HttpTransportBindingElement { MaxReceivedMessageSize = int.MaxValue });
                }
            }
    
    

  • Wednesday, September 09, 2009 7:49 PMeSchlosser Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Ok That was simple, But I get the same error almost immediately in the override Message ReadMessage method.

    I actually get a “Error creating a reader for the MTOM Message” but the inner exception is almost the same as before, “The maximum buffer size (65536) has been exceeded…"

    Instead of your way

    return new CustomBinding(

                       new MyNewEncodingBindingElement(),

    new HttpTransportBindingElement { MaxReceivedMessageSize = int.MaxValue });

     

    I tried this

    CustomBibding CB = new CustomBinding(

                       new MyNewEncodingBindingElement(),

    new HttpTransportBindingElement () );

          CB.Elements.Find<TransportBindingElement>(). MaxReceivedMessageSize = int.MaxValue;

     

     and got the same result.  Is there another way of setting it?

    Thank you for your Help inadvance,

    Eric


    E Schlosser
  • Wednesday, September 09, 2009 8:25 PMCarlos FigueiraMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    You may need to increase MaxBufferSize as well:

            static Binding GetBinding(bool useCustomEncoder)
            {
                HttpTransportBindingElement httpBE = new HttpTransportBindingElement();
                httpBE.MaxBufferSize = int.MaxValue;
                httpBE.MaxReceivedMessageSize = int.MaxValue;
                if (useCustomEncoder)
                {
                    return new CustomBinding(
                        new MyNewEncodingBindingElement(),
                        httpBE);
                }
                else
                {
                    return new CustomBinding(
                        new MtomMessageEncodingBindingElement(),
                        httpBE);
                }
            }
    
    
  • Wednesday, September 09, 2009 9:09 PMeSchlosser Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Carlos,

    Still the same problem. I think the problem lies in the fact that the code inside the ELSE block that cerates the MTOM binding never gets executed. As far as I can see GetBinding only gets called with a True value.

    That begs to ask, how is the MTOM binding getting created?





    UpDate:  I found where to fix this, it is the MyNewEncoder method. same fix as above but in that location. Got a new problem but Im working on it.


    E Schlosser
  • Tuesday, September 15, 2009 5:02 PMeSchlosser Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Carlos,

    I am still having one problem. It is in deserializing the Mime document. The reply coming in on the wire looks like this…

    <body>

                <RetrieveImageResponse>

                            <ScanData>

                                        <xop:Include Href =”cid:1@body”></xop:include>

                            </ScanData>

                </RetrieveImageResponse>

    </body>

    ..7d..—993c23400-1dd2-11b2-8d4e-e93374a1c48e..Content-Type: image/jfif..Content-Transfer-Encoding: binary..Content-ID: <1@body> data

     

    My current Message Contract looks as follows

    [MessageContract(IsWrapped = false)]

        public class RetrieveImageResponseMessage

        {

            [MessageBodyMember(Name = "RetrieveImageResponse", Namespace = StringConst.WSDScanNamespace)]

            public RetrieveImageResponseType RetrieveImageResponse;

        }

     

        [XmlRoot("RetrieveImageResponse", Namespace = StringConst.WSDScanNamespace)]

        public class RetrieveImageResponsetype

        {

            [XmlElement("ScanData")]

            public byte[] ScanData;

     

            [XmlAnyElement]

            public XmlElement[] AnyElements;

     

            [XmlAnyAttributeAttribute()]

            public XmlAttribute[] AnyAttributes;

        }

     

     

    I have rearanged this many different ways. I have used DataContracts. I have tried several combinations. All to no avail.

    I need the Content-Type And the binary data. Any ideas?

    Eric

  • Thursday, September 24, 2009 6:21 PMeSchlosser Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Carlos,everyone, This last issue turned out it was a FW defect from the scanner, not creating the mime boundry delimiter correctly. As for the rest of the code, I had to change the ReadQuota.MaxArrayLength = int.MaxValue. Added it right below the MaxBufferSize change (see above) and now everything works Great! Thank you Carlos! Eric
    E Schlosser
    • Marked As Answer byeSchlosser Thursday, September 24, 2009 6:21 PM
    •  
  • Tuesday, November 03, 2009 8:31 PMDaveBrask Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi Carlos,

    I wrote a similar version for VB and called it MixedBindingEelement.  My curent config looks like this:
    <bindingElementExtensions><add name="MixedEncoding" type="MixedBindingEelement, MixedEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /></bindingElementExtensions>

    and this:
    <wsHttpBinding><binding name="AttachmentServiceSoapBinding" maxReceivedMessageSize="67108864" messageEncoding="Mtom"><readerQuotas maxArrayLength="67108864" /></binding></wsHttpBinding>

    How to I tell it to use the custom encoder?

    Dave

     

     

  • Wednesday, November 18, 2009 5:08 PMaurealus2 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    Hi Dave,

    Take a look at the WCF Samples http://go.microsoft.com/fwlink/?LinkId=87352 , specifically:
    Samples\WCFWFCardSpace\WCF\Extensibility\MessageEncoder\Text\CS\CustomTextMessageEncoder.sln

    This will show you everything that needs to be created in order to use a custom binding and encoding as well as the capability to use it in your config file.  Below is my config file for the custom binding I created.
    <system.serviceModel>
      <client>
    	<endpoint address="http://10.8.28.11:8080/imageupload/upload" binding="customBinding" bindingConfiguration="MixedMessageBinding" contract="Services.Soap.FileUpload.FileUploadPortType" name="FileUploadPort"/>
      </client>
      <bindings>
    		<customBinding>
    		  <binding name="MixedMessageBinding">
    			<mixedMessageEncoding messageVersion="Soap12" encoding="utf-8">
    			  <readerQuotas maxDepth="32" maxStringContentLength="8192" 
    							maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
    			</mixedMessageEncoding>
    			<httpTransport manualAddressing="false" maxBufferPoolSize="524288"
    			  maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
    			  bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
    			  keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
    			  realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
    			  useDefaultWebProxy="true" />    
    		  </binding>
    		</customBinding>
    	</bindings>
    
    	<extensions>
    	  <bindingElementExtensions>
    		<add name="mixedMessageEncoding" type="WCF.MixedMessageEncodingElement,
    			 WcfMixedMessageEncoder"/>
    	  </bindingElementExtensions>
    	</extensions>
    </system.serviceModel>
    
  • Sunday, November 22, 2009 7:03 PMDaveBrask Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thanks aurealus2  Looking at your example and the samples finally got me to a resolution.  I needed one of these:
    ' Binding Extension
    Public Class MixedMessageEncodingExtension
        Inherits ServiceModel.Configuration.BindingElementExtensionElement
        Public Sub New()
            MyBase.New()
        End Sub
        Public Overrides ReadOnly Property BindingElementType() As System.Type
            Get
                Return GetType(MixedEncodingBindingEelement)
            End Get
        End Property
        Protected Overrides Function CreateBindingElement() As System.ServiceModel.Channels.BindingElement
            Dim bindingElement As New MixedEncodingBindingEelement
            Me.ApplyConfiguration(bindingElement)
            Return bindingElement
        End Function
    End Class