简体   繁体   中英

Error “Content-Type header from MTOM message not found” in custom message encoder c#

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

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;

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM