【问题标题】:Error "Content-Type header from MTOM message not found" in custom message encoder c#自定义消息编码器 c# 中的错误“未找到来自 MTOM 消息的 Content-Type 标头”
【发布时间】:2015-10-26 15:28:07
【问题描述】:

我有一个 C# 客户端应用程序,它需要使用 Java 编码的第三方 Web 服务,响应是 MTOM。当我使用本机消息编码器并配置 basicHttpBinding 时,我收到错误“字符集元素的内容长度...”。好吧,第三方服务(或网络服务器容器)没有发送字符集,所以我决定创建一个自定义消息编码器和自定义绑定来捕获来自网络服务器的响应,添加缺少的字符集并发送到应用层,但是当我处理我添加字符集的消息时,我收到一个错误“未找到来自 MTOM 消息的 Content-Type 标头”。

这是我做的:

首先,我创建了一些类来处理消息:
- CustomMtomBindingElementExtensionElement 扩展 BindingElementExtensionElement
- CustomMtomMessageEncodingBindingElement 扩展 MessageEncodingBindingElement 并实现 IWsdlExportExtension
- CustomMtomMessageEncoderFactory 扩展 MessageEncoderFactory
- CustomMtomMessageEncoder 扩展 MessageEncoder

在 CustomMtomMessageEncoder 中,我有一个私有属性,用于在添加字符集后处理修改后的消息:

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...
}

在同一个类中,我重写了 ReadMessage 方法:

    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;
    }

错误发生在指示行“Message mensagem = this.mtomEncoder.ReadMessage(newBuffer, bufferManager);”

请帮忙。

谢谢,

卢西亚诺·内里

【问题讨论】:

  • 我遇到了同样的事情,我注意到的一件事是 WCF 生成的 MTOM 请求在 bod 中有这个。 MIME 版本:1.0 内容类型:multipart/related;type="application/xop+xml";boundary="9a7b8f09-41a7-4cf9-b3a8-0e490e38890e+id=6";start="tempuri.org/0/…" 其中我认为它是 mtom 编码器试图找到的。

标签: c# mtom


【解决方案1】:

解决方案是在调用 InnerEncoder.ReadMessage 之前将内容类型(ReadMessage 参数的一部分)附加到字节数组的开头。这是不符合 SOAP 标准的 Microsoft WCF。请注意,我正在使用 VS2015。 bytesToEncode 是 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;

【讨论】:

【解决方案2】:

这个问题很老了,但我还是想回答它,因为可能会有更多的人在寻找答案:

您需要将 contentType 字符串传递给 mtomEncoder.ReadMessage 函数。 比它会工作。

如果您在 ReadMessage 函数中进行了更多更改,您可能需要更改 contentTypestring 中的相同内容 - 但不要担心,您将收到一个干净的异常,这将帮助您解决问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-19
    • 1970-01-01
    • 2013-08-05
    • 1970-01-01
    • 2015-08-27
    • 1970-01-01
    • 1970-01-01
    • 2016-06-16
    相关资源
    最近更新 更多