none
Malformed MTOM (duplicate Content-Type header) when using custom encoder

    Question

  • Hi,

    I am using a custom encoder on the client side to communicate with a new server.  In the past, other endpoints have accepted our messages just fine, but a new implementation we communicate with (implemented on JAX-WS) is complaining because we send two Content-Type headers, one of which is incomplete - does not have mime boundary information. Here is a wireshark trace of what we are sending:

    POST /dev-ce/wcf/respondinggateway.svc/mtom HTTP/1.1
    Host: 192.168.190.119
    Content-Type: multipart/related; type="application/xop+xml"
    Expect: 100-continue
    Via: 1.1 dev.myorg.org
    X-Forwarded-For: 192.168.190.119
    X-Forwarded-Host: dev.myorg.org
    X-Forwarded-Server: dev.myorg.org
    Connection: Keep-Alive
    Content-Length: 9639

    MIME-Version: 1.0
    Content-Type: multipart/related;type="application/xop+xml";boundary="dfaaeaeb-d839-4884-b8d8-111975550b7e+id=2";start="<http://tempuri.org/0/634243983490693389>";start-info="application/soap+xml"

    --dfaaeaeb-d839-4884-b8d8-111975550b7e+id=2
    Content-ID: <http://tempuri.org/0/634243983490693389>
    Content-Transfer-Encoding: 8bit
    Content-Type: application/xop+xml;charset=utf-8;type="application/soap+xml"

    ... SOAP Content ...

     

    The methods that control our outgoing request message are simply delegating to the innerEncoder object (we have MtomMessageEncoder configured).  We only need the encoder to do processing on the reply.  Here are our implementations of the write method, and ContentType property:

     

        public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
        {
          //Use the inner encoder to encode a Message into a buffered byte array
          ArraySegment<byte> buffer = innerEncoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
    
          string messageContents = Utf8Encoding.GetString(buffer.Array, 0, buffer.Count);
    
          System.Diagnostics.Debug.WriteLine(messageContents, "Original WCF Request Message (Mtom Encoded)");
    
          return buffer;
        }
    
    
        public override string ContentType
        {
          get { return innerEncoder.ContentType; }
        }
    
    
    

    When we plug in the MtomMessageEncoder directly, we produce well formed http headers, and the responding system replies perfectly, but we fail on the response without the custom encoder.  Is there something I am doing wrong when writing the outgoing message?  Why isn't my custom encoder behaving like the MtomMessageEncoder that we are delegating to?

     

    Just a little more info on the research I've done so far...

    http://msdn.microsoft.com/en-us/library/ms735115.aspx -- Excerpt Below

    To work correctly with HTTP, the internal MTOM message encoder class provides some internal APIs for GetContentType (which is also internal) and WriteMessage , which is public and can be overridden. More communication must occur to ensure values in the HTTP headers agree with values in the MIME headers.

     

    It seems like this is getting at the root of my problem, but when using the custom encoder, the communication between methods is not happening properly.  Just thought it may have something to do with my problem

     

    Thanks in advance!

    Friday, November 05, 2010 12:55 PM

All replies

  • This is still causing us issues.  I'm trying to piece together what I can from Reflector, but I feel like I'm just spinning my wheels at this point.  Any ideas on what might be going wrong, or how to fix it?

     

    Here is the fault that being returned:

    --- Inner exception : Level 1 ---
    FaultException: Couldn't create SOAP message due to exception: javax.xml.ws.WebServiceException: MIME boundary parameter not foundmultipart/related; type="application/xop+xml"
    --- End of inner exception list ---

     

    The feedback from receiving endpoint that they are picking up the first Content-Type header, which does not contain the Mime boundary information.  As posted originally:

    POST /dev-ce/wcf/respondinggateway.svc/mtom HTTP/1.1
    Host: 192.168.190.119
    Content-Type: multipart/related; type="application/xop+xml"
    Expect: 100-continue
    Via: 1.1 dev.myorg.org
    X-Forwarded-For: 192.168.190.119
    X-Forwarded-Host: dev.myorg.org
    X-Forwarded-Server: dev.myorg.org
    Connection: Keep-Alive
    Content-Length: 9639

    MIME-Version: 1.0
    Content-Type: multipart/related;type="application/xop+xml";boundary="dfaaeaeb-d839-4884-b8d8-111975550b7e+id=2";start="<http://tempuri.org/0/634243983490693389>";start-info="application/soap+xml"

    --dfaaeaeb-d839-4884-b8d8-111975550b7e+id=2
    Content-ID: <http://tempuri.org/0/634243983490693389>
    Content-Transfer-Encoding: 8bit
    Content-Type: application/xop+xml;charset=utf-8;type="application/soap+xml"

    ... SOAP Content ...

     

     

    Tuesday, November 09, 2010 9:35 PM
  • Hi,

    Could you show the working request as well? Please highlight the difference between the working/non-working message.

     


    Please remember to mark the replies as answers if they help and unmark them if they provide no help. Windows Azure Platform China Blog: http://blogs.msdn.com/azchina/default.aspx

    Friday, November 12, 2010 8:37 AM
    Moderator
  • Is it possible for you to provide the custom MTOM encoder implementation? You can send me via mail at piyush.joshi AT microsoft.com. Thanks.
    - Piyush
    Saturday, November 13, 2010 12:32 AM
    Owner
  • Hi,

    did this result in a solution? I have the same problem.

    I want to create a WCF service which supports Text en MTom so I created a MixedMessageEncoder which should return MTOM if the request is MTOM and Text if the input of Text. This is out of the box functionality in WSE3 (by setting mtom server mode is optional). My first step is to support MTOM only in the MixedMessageEncoder. I used the implementation which can be found at http://forge.osor.eu/plugins/scmsvn/viewcvs.php/*checkout*/dotnet/transportLibrary/trunk/START/STARTLibrary/Encoding/MixedContentTypeMessageEncoder.cs?root=peppol&rev=3033&pathrev=3612 

    This works well when I use a WCF client which sends MTOM but it doesn't work when I use WSE (I need this since the client uses XP embeded). When I look at the HTTP message using fiddler I see the following difference:

    The response which is accepted by a WSE client (using basicHTTPBinding and mtom encoding):

    HTTP/1.1 200 OK
    Content-Length: 1155
    Content-Type: multipart/related;type="application/xop+xml";start="<
    http://tempuri.org/0>";boundary="uuid:0893f6e0-1b6c-44e4-9d2d-4219f254d8ef+id=1";
    start-info="text/xml"
    Server: Microsoft-IIS/7.5
    MIME-Version: 1.0
    X-Powered-By: ASP.NET
    Date: Tue, 15 Feb 2011 14:28:06 GMT


    --uuid:0893f6e0-1b6c-44e4-9d2d-4219f254d8ef+id=1
    Content-ID: <
    http://tempuri.org/0>
    Content-Transfer-Encoding: 8bit
    Content-Type: application/xop+xml;charset=utf-8;type="text/xml"

    <Soap ...>

    The response which isn't accepted

    HTTP/1.1 200 OK
    Content-Length: 1369
    Server: Microsoft-IIS/7.5
    X-Powered-By: ASP.NET
    Date: Tue, 15 Feb 2011 15:56:16 GMT

    MIME-Version: 1.0
    Content-Type: multipart/related;type="application/xop+xml";boundary="0a6c53f8-ee5f-4d6d-86ca-cc0f3b525378+id=1";start="<
    http://tempuri.org/0/634333857769660588>";start-info="text/xml"

    --0a6c53f8-ee5f-4d6d-86ca-cc0f3b525378+id=1
    Content-ID: <
    http://tempuri.org/0/634333857769660588>
    Content-Transfer-Encoding: 8bit
    Content-Type: application/xop+xml;charset=utf-8;type="text/xml"

    <Soap ...>

    It looks like the following code:

     

     

    public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)

    {

     

     

    ArraySegment<byte> output = this.mtomEncoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);

     

     

    return output;

    }

    Fills everything in the HTTP body, while the first part should be in the HTTP header.

    If you don't have a solution I will have to start using WSE also which I don't want.

    Thanks,

    Ren'e 


    rt
    Tuesday, February 15, 2011 9:37 PM
  • I had the same problem last week, so I posted a solution in my blog at http://blogs.msdn.com/b/carlosfigueira/archive/2011/02/16/using-mtom-in-a-wcf-custom-encoder.aspx. Essentially, you'll need to override the message serialization instead of simply delegating it to the inner MTOM encoder. The post has more information about it.
    • Proposed as answer by Carlos Figueira Wednesday, February 16, 2011 5:26 AM
    Wednesday, February 16, 2011 5:26 AM
  • Excellent. Thanks a lot. Don't think I could does this my self.

    I do have one more question. When I upload a huge file I get the error:

    The maximum array length quota (16384) has been exceeded while reading XML data. T

    Normally you can adjust this in the configuration but since this is a custom encoder it doesn't seem to work.

    This is in my config:

    <customBinding>
    	<binding name="TextOrMtomBinding">
         		<textOrMtomEncoding messageVersion="Soap11">
           		<readerQuotas maxDepth="32" maxStringContentLength="8192"
              		maxArrayLength="204800000" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
          </textOrMtomEncoding>
          <httpTransport
             maxBufferSize="2000000000"
             maxReceivedMessageSize="2000000000"
             transferMode="Buffered"
             authenticationScheme="Anonymous"
      	  />
    

    I also do this in the element extension

     public override void ApplyConfiguration(BindingElement bindingElement)
        {
     	  base.ApplyConfiguration(bindingElement);
          TextOrMtomEncodingBindingElement binding = (TextOrMtomEncodingBindingElement)bindingElement;
          binding.MessageVersion = this.MessageVersion;
          //binding.Encoding = this.Encoding;
          this.ApplyConfiguration(binding.ReaderQuotas);
        }
    

    And this in the element

    public TextOrMtomEncodingBindingElement(MessageVersion msgVersion)
        {
          if (msgVersion == null)
          	throw new ArgumentNullException("msgVersion");
    
          this.MessageVersion = msgVersion;
          this.readerQuotas = new XmlDictionaryReaderQuotas();
        }
    
    

    So the binding is ok. But it looks like the mtom binding doesn't use it.

    How can I configure this?

    Thanks,

    Rene


    rt
    Wednesday, February 16, 2011 2:08 PM
  • Ok, I found it. You have to pass the readerquotes to the standard encoders. Unfortunantly there's no constructor for this so you have to set the property.

    class TextOrMtomEncoder : MessageEncoder
      {
        MessageEncoder _textEncoder;
        MessageEncoder _mtomEncoder;
        public TextOrMtomEncoder(MessageVersion messageVersion, XmlDictionaryReaderQuotas readerQuotas)
        {
          TextMessageEncodingBindingElement textEncoderBindingElement = new TextMessageEncodingBindingElement(messageVersion, Encoding.UTF8);
          MtomMessageEncodingBindingElement mtomEncoderBindingElement = new MtomMessageEncodingBindingElement(messageVersion, Encoding.UTF8);
          
          readerQuotas.CopyTo(mtomEncoderBindingElement.ReaderQuotas);
          readerQuotas.CopyTo(textEncoderBindingElement.ReaderQuotas);
        
          _mtomEncoder = mtomEncoderBindingElement.CreateMessageEncoderFactory().Encoder;
          _textEncoder = textEncoderBindingElement.CreateMessageEncoderFactory().Encoder;
        }
    

    Carlos, thanks again.

    Rene 


    rt
    • Proposed as answer by René Titulaer Wednesday, February 16, 2011 3:42 PM
    Wednesday, February 16, 2011 2:33 PM