我有一个自定义编码器连接到customBinding
水下使用TextMessageEncoding
元素。我明确指出SOAP 1.1应该与WS Addressing 1.0一起使用。正如我所说,我的自定义编码器在水下使用文本消息编码器;编码器只是添加了一些调用我的服务的服务实现的标头。
当我在SOAPUI中添加生成的WSDL(使用SOAP 1.2,即使我在WS Addressing 1.0中指定了SOAP 1.1)并发送请求时,内容类型也不同,从而导致错误。我认为这是因为WHILE生成WSDL,它使用Soap 1.2,但WHILE发送请求它尝试使用SOAP 1.1,即使使用SOAP 1.2发送消息。
有一些相关问题:
当我第一次使用<textMessageEncoding messageVersion="Soap11WSAddressing10" writeEncoding="utf-8" />
时,将WSDL添加到SOAPUI,然后将编码更改为我的自定义编码器并发送请求(这导致WSDL成为Soap 1.1所以我想也许这会是一个非常hacky解决方法),我收到以下错误:
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'.
UTF-8
是大写的,;
后面有空格。我觉得这很奇怪,应该不是问题! 在Visual Studio中,自定义编码器有一条波浪线,表示The element 'binding' has invalid child element 'MissingWSAddressingHeadersTextEncoding'. List of possible elements expected: context, ....
我查看了this Stackoverflow post并使用了UI编辑器,但是波浪线仍然存在。我还编辑了我的DotNetConfig.xsd
我100%确信地址是正确的,因为在运行时自定义编码器工作正常。
请查看我的代码。代码中提供的链接是我用来创建编码器的链接。
namespace DigipoortConnector.Api.Digipoort_Services.Extensions
{
public class WSAddressingEncodingBindingElementExtension : BindingElementExtensionElement
{
public override Type BindingElementType => typeof(WSAddressingEncodingBindingElement);
protected override BindingElement CreateBindingElement()
{
return new WSAddressingEncodingBindingElement();
}
}
}
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);
}
}
}
}
<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>
我唯一可以假设导致此问题的是在BUILD TIME(当生成WSDL时?)我的自定义编码器未正确使用。但是在运行时它会被使用,即使用于生成WSDL(具有默认SOAP 1.2的Textencoder)的回退编码器期望1.2 ......?
我尝试过使用WCF GUI编辑器(右键单击web.config
并选择Edit WCF configuration
)。当我打开它时,它说我的自定义编码器的DLL无法找到。我可以继续手动添加它,但保存并重新启动编辑器会产生相同的结果。检查我的自定义绑定并选择我的自定义编码器时,它没有显示任何结果:
虽然这也可能是因为我的编码扩展类没有任何其他属性..
我在这里完全不知所措!请帮我解决这个问题!
答案 0 :(得分:0)
@gnud的回答是修复!
实施IWsdlExportExtension
界面。
按照Encoder,BindingElement和Factory的MS文档进行操作。