WCF自定义消息编码器使用Soap1.2,即使我明确指定了1.1 [英] WCF Custom Message Encoder uses Soap1.2 even though I explicitly specify 1.1

查看:103
本文介绍了WCF自定义消息编码器使用Soap1.2,即使我明确指定了1.1的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义编码器,它连接到 customBinding ,该编码器在水下使用 TextMessageEncoding 元素.我特别指定SOAP 1.1应该与WS Addressing 1.0一起使用.正如我所说,我的自定义编码器在水下使用文本消息编码器;编码器仅添加一些调用我的服务的服务要实现的标头.

当我在SOAPUI中添加生成的WSDL(使用SOAP 1.2,即使我使用WS Addressing 1.0指定了SOAP 1.1)时,它也会发送请求,但内容类型不同,这会导致错误.我认为这是因为生成WSDL时,它使用的是Soap 1.2,但是即使发送消息是使用SOAP 1.2来发送的,它也会尝试使用SOAP 1.1.

有一些相关问题:

  • 当我第一次使用< textMessageEncoding messageVersion =" Soap11WSAddressing10"writeEncoding ="utf-8";/> ,将WSDL添加到SOAPUI,然后将编码更改为我的自定义编码器并发送请求(这导致WSDL为Soap 1.1,所以我认为这可能是一个非常棘手的解决方法),出现以下错误:

    • HTTP/1.1 415无法处理消息,因为内容类型'text/xml; charset = UTF-8'不是预期的类型'text/xml;charset = utf-8'.

      • 这里的问题是 UTF-8 是大写的,并且之后有空格;.我认为这很奇怪,不应该成为问题!
  • 在Visual Studio中,自定义编码器有一条弯曲的行,表示元素"binding"具有无效的子元素"MissingWSAddressingHeadersTextEncoding".预期的可能元素列表:上下文,....我看过

    尽管这也可能是因为我的编码扩展类没有任何其他属性.

    我在这里完全茫然!请帮我解决这个问题!

    解决方案

    @gnud的答案就是解决方法!

    实施 IWsdlExportExtension 接口.

    按照Encoder,BindingElement和Factory的MS文档进行操作.

    https://docs.microsoft.com/zh-CN/dotnet/api/system.servicemodel.channels.messageencodingbindingelement?view = netframework-4.7.1

    https://docs.microsoft.com/zh-cn/dotnet/api/system.servicemodel.channels.messageencoderfactory?view = netframework-4.7.1

    https://docs.microsoft.com/zh-cn/dotnet/api/system.servicemodel.channels.messageencoder?view = netframework-4.7.1

    I have a custom encoder hooked up to a customBinding that uses a TextMessageEncoding element underwater. I specified specifically that SOAP 1.1 should be used with WS Addressing 1.0. My custom encoder, as I said, uses a text message encoder underwater; the encoder just adds some headers that the service that calls my service wants implemented.

    When I add the generated WSDL (that uses SOAP 1.2, even though I specified SOAP 1.1 with WS Addressing 1.0) in SOAPUI and send a request, the content-type is different and it causes an error. I presume this is because WHILE generating the WSDL, it uses Soap 1.2, but WHILE sending a request it tries to use SOAP 1.1 even though a message is send using SOAP 1.2.

    There are a few related issues:

    • When I FIRST use <textMessageEncoding messageVersion="Soap11WSAddressing10" writeEncoding="utf-8" />, add the WSDL to SOAPUI, then change the the encoding to my custom encoder and send a request (Which results in the WSDL being Soap 1.1 so I thought maybe this would be a very hacky workaround) , I get the following error:

      • HTTP/1.1 415 Cannot process the message because the content type 'text/xml;charset=UTF-8' was not the expected type 'text/xml; charset=utf-8'.

        • The issue here is that UTF-8 is in uppercase and that there is whitespace after the ; . I think this is rather weird and should not be an issue!
    • In Visual Studio custom encoder has a squiggly line that says The element 'binding' has invalid child element 'MissingWSAddressingHeadersTextEncoding'. List of possible elements expected: context, .... I have looked at this Stackoverflow post and used the UI editor, but the squiggly line stays. I have also edited my DotNetConfig.xsd I am 100% confident the address is correct because at run-time the custom encoder works fine.

    Please take a look at my code. The links provided in the code are the ones I used to create the encoder.

    The class that is used as the extension

    namespace DigipoortConnector.Api.Digipoort_Services.Extensions
    {
        public class WSAddressingEncodingBindingElementExtension : BindingElementExtensionElement
        {
            public override Type BindingElementType => typeof(WSAddressingEncodingBindingElement);
    
            protected override BindingElement CreateBindingElement()
            {
                return new WSAddressingEncodingBindingElement();
            }
        }
    }
    

    The element, factory and encoder

    namespace DigipoortConnector.Api.Digipoort_Services.Extensions
    {
    //https://msdn.microsoft.com/en-us/library/system.servicemodel.channels.messageencoder(v=vs.110).aspx
    //https://blogs.msdn.microsoft.com/carlosfigueira/2011/11/08/wcf-extensibility-message-encoders/
    
    public class WSAddressingEncodingBindingElement : MessageEncodingBindingElement
    {
        public override MessageEncoderFactory CreateMessageEncoderFactory() => new WSAddressingEncoderFactory();
    
        public override MessageVersion MessageVersion
        {
            get => MessageVersion.Soap11WSAddressing10;
            set
            {
                if (value != MessageVersion.Soap11WSAddressing10)
                {
                    throw new ArgumentException("Invalid message version");
                }
            }
        }
    
        public override BindingElement Clone() => new WSAddressingEncodingBindingElement();
    
        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>();
        }
    
        private class WSAddressingEncoderFactory : MessageEncoderFactory
        {
            private MessageEncoder _encoder;
    
            public override MessageEncoder Encoder
            {
                get
                {
                    if (_encoder == null)
                    {
                        _encoder = new WSAddressingEncoder();
                    }
    
                    return _encoder;
                }
            }
    
            public override MessageVersion MessageVersion => MessageVersion.Soap11WSAddressing10;
        }
    
        private class WSAddressingEncoder : MessageEncoder
        {
            private MessageEncoder _underlyingEncoder;
            private const string AddressingNamespace = "http://www.w3.org/2005/08/addressing";
    
            public WSAddressingEncoder()
            {
                _underlyingEncoder = new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressing10, Encoding.UTF8)
                    .CreateMessageEncoderFactory().Encoder;
            }
    
            public override string ContentType => _underlyingEncoder.ContentType;//.Replace("utf-8", "UTF-8").Replace("; ", ";"); //The replaces are used to fix the uppecase/; problem
    
            public override string MediaType => _underlyingEncoder.MediaType;
    
            public override MessageVersion MessageVersion => _underlyingEncoder.MessageVersion;
    
            public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
                => _underlyingEncoder.ReadMessage(stream, maxSizeOfHeaders, contentType);
    
            public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
                => _underlyingEncoder.ReadMessage(buffer, bufferManager, contentType);
    
            public override void WriteMessage(Message message, Stream stream)
                => _underlyingEncoder.WriteMessage(message, stream);
    
            public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
            {
                message.Headers.Add(MessageHeader.CreateHeader("To", AddressingNamespace, "http://www.w3.org/2005/08/addressing/anonymous"));
    
                var relatesToHeaderValue = message.Headers.RelatesTo?.ToString();
                message.Headers.Add(MessageHeader.CreateHeader("MessageID", AddressingNamespace, relatesToHeaderValue));
    
                return _underlyingEncoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
            }
        }
    }
    

    }

    The binding and the extension element

    <customBinding>
          <binding>
            <security
              authenticationMode="CertificateOverTransport"
              messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"
              enableUnsecuredResponse="false"
              messageProtectionOrder="EncryptBeforeSign"
              includeTimestamp="true"
              defaultAlgorithmSuite="TripleDesRsa15" />
            <missingWSAddressingHeadersTextEncoding />
            <httpsTransport requireClientCertificate="true" />
          </binding>
    </customBinding>
    
    <extensions>
      <bindingElementExtensions>
        <add name="missingWSAddressingHeadersTextEncoding" type="DigipoortConnector.Api.Digipoort_Services.Extensions.WSAddressingEncodingBindingElementExtension, DigipoortConnector.Api"/>
      </bindingElementExtensions>
    </extensions>
    

    The only thing I can assume that causes this issue is that at BUILD TIME (When the WSDL will be generated?) my custom encoder is NOT used correctly. But then at run-time it will be used, even though the fallback encoder that was used to generate the WSDL (Textencoder with default SOAP 1.2) is expecting 1.2...?

    I have tried using the WCF GUI editor (Right click on web.config and select Edit WCF configuration). When I open it, it says that the DLL of my custom encoder can't be found. I can go ahead and add it manually, but saving and restarting the editor yields the same result. When inspecting my custom binding and selecting my custom encoder, it shows no results:

    Although this could also be because my encoding extension class does not have any other properties..

    I am totally at a loss here! Please help me figure this out!

    解决方案

    @gnud 's answer was the fix!

    Implement the IWsdlExportExtension interface.

    Follow the MS docs of the Encoder, BindingElement and Factory.

    https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.messageencodingbindingelement?view=netframework-4.7.1

    https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.messageencoderfactory?view=netframework-4.7.1

    https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.messageencoder?view=netframework-4.7.1

    这篇关于WCF自定义消息编码器使用Soap1.2,即使我明确指定了1.1的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆