1

I have a client application in C# that needs to consume a third party web service coded in Java, and the response is MTOM. When I uses native message encoder and configure basicHttpBinding, I receivced error "the content length of charset element...". Well, the third party service (or the web server container) is not sending the charset, so I decided to create a custom message encoder and custom binding for to capture the response from web server, adds missing charset and send to application layer, but when i process the message I added charset, I received an error "Content-Type header from MTOM message not found".

Here is what I maded:

First, I have created some classes to work with message:
- CustomMtomBindingElementExtensionElement extending BindingElementExtensionElement
- CustomMtomMessageEncodingBindingElement extending MessageEncodingBindingElement and implementing IWsdlExportExtension
- CustomMtomMessageEncoderFactory extending MessageEncoderFactory
- CustomMtomMessageEncoder extending MessageEncoder

In CustomMtomMessageEncoder i have a private attributte used to process the modified message after add charset:

public class CustomMtomMessageEncoder : MessageEncoder
{
    private MessageEncoder mtomEncoder;
    private CustomMtomMessageEncoderFactory factory;
    private XmlWriterSettings writerSettings;
    private string contentType;

    public CustomMtomMessageEncoder(CustomMtomMessageEncoderFactory factory)
    {
        this.factory = factory;
        this.writerSettings = new XmlWriterSettings();
        this.contentType = string.Format("{0}; charset={1}", this.factory.MediaType, this.writerSettings.Encoding.HeaderName);

        MtomMessageEncodingBindingElement mtomBindingElement = new MtomMessageEncodingBindingElement(this.MessageVersion, Encoding.GetEncoding(this.factory.CharSet));

        this.factory.ReaderQuotas.CopyTo(mtomBindingElement.ReaderQuotas);
        this.mtomEncoder = mtomBindingElement.CreateMessageEncoderFactory().Encoder;
    }

    //Other things...
}

In same class, i overrides ReadMessage method:

    public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
    {
        //Convert the received buffer into a string
        byte[] incomingResponse = buffer.Array;

        //read the first 500 bytes of the response
        string strFirst500 = System.Text.Encoding.UTF8.GetString(incomingResponse, 0, 500);

        //Check the last occurance of 'application/xop+xml' in the response. We check for the last
        //occurrence since the first one is present in the Content-Type HTTP Header. Once found,
        //append charset header to this string
        int appIndex = strFirst500.LastIndexOf("application/xop+xml");
        string modifiedResponse = strFirst500.Insert(appIndex + 19, "charset=utf-8");

        modifiedResponse = modifiedResponse.Replace("application/xop+xmlcharset=utf-8", "application/xop+xml; charset=utf-8");

        //convert the modified string back into a byte array
        byte[] ma = System.Text.Encoding.UTF8.GetBytes(modifiedResponse);

        //integrate the modified byte array back to the original byte array
        int increasedLength = ma.Length - 500;
        byte[] newArray = new byte[incomingResponse.Length + increasedLength];

        for (int count = 0; count < newArray.Length; count++)
        {
            if (count < ma.Length)
            {
                newArray[count] = ma[count];
            }
            else
            {
                newArray[count] = incomingResponse[count - increasedLength];
            }
        }

        //In this part generate a new ArraySegment<byte> buffer and pass it to the underlying MTOM Encoder.
        ArraySegment<byte> newBuffer = new ArraySegment<byte>(newArray);

        /*##### Here the error is triggered with message "can not create mtom reader for message" and inner exception is "Content-Type header from mtom message not found" #####*/
        Message mensagem = this.mtomEncoder.ReadMessage(newBuffer, bufferManager);

        return mensagem;
    }

The error occurs in indicated line "Message mensagem = this.mtomEncoder.ReadMessage(newBuffer, bufferManager);"

Please help.

Thanks,

Luciano Nery

Luciano Nery
  • 351
  • 2
  • 5
  • I encountered the same thing, one thing I noticed is that the WCF generated MTOM request has this in the bod. MIME-Version: 1.0 Content-Type: multipart/related;type="application/xop+xml";boundary="9a7b8f09-41a7-4cf9-b3a8-0e490e38890e+id=6";start="";start-info="application/soap+xml" Which I think it what the mtom encoder is trying to find. – MichaelChan Jun 09 '16 at 03:54

2 Answers2

0

The solution to this is to append the content type (which is part of ReadMessage parameters) to the beginning of the byte array before calling InnerEncoder.ReadMessage. This is Microsoft WCF not complying with SOAP standards. Mind that I'm using VS2015. bytesToEncode is the buffer.Array.

const string ContentTypeHeader = "content-type";
var encoding = new UTF8Encoding(false);
var header = $"{ContentTypeHeader}: {headerValue}{Environment.NewLine}";
var headerBytes = encoding.GetBytes(header);

var contentWithHeader = new byte[headerBytes.Length + bytesToEncode.Length];
Buffer.BlockCopy(headerBytes, 0, contentWithHeader, 0, headerBytes.Length);
Buffer.BlockCopy(bytesToEncode, 0, contentWithHeader, headerBytes.Length, bytesToEncode.Length);
return contentWithHeader;
MichaelChan
  • 1,808
  • 17
  • 34
  • I added content type to message, but not the way you suggested, can you post an example please? – Luciano Nery Jun 28 '16 at 09:49
  • Convert the content type into byte[] (http://stackoverflow.com/questions/16072709/converting-string-to-byte-array-in-c-sharp) then combine the buffer.Array (http://stackoverflow.com/questions/415291/best-way-to-combine-two-or-more-byte-arrays-in-c-sharp) – MichaelChan Jun 28 '16 at 21:13
0

This question is very old, but still i'd like to answer it, because there might be some more ppl looking for an answer:

You need to pass the contentType string to the mtomEncoder.ReadMessage function. Than it will work.

In case you changed more in your ReadMessage function you might have to change the same things in the contentTypestring - but dont worry, you will receive a clean exception which will help you to fix your problem.

Qerildan
  • 1
  • 5