O codificador de mensagens personalizadas do WCF usa o Soap1.2, embora eu especifique explicitamente 1.1
Eu tenho um codificador personalizado conectado a umcustomBinding
que usa umTextMessageEncoding
elemento debaixo d'água. Especifiquei especificamente que o SOAP 1.1 deve ser usado com o WS Addressing 1.0. Meu codificador personalizado, como eu disse, usa um codificador de mensagens de texto embaixo d'água; o codificador apenas adiciona alguns cabeçalhos que o serviço que chama meu serviço deseja implementar.
Quando adiciono o WSDL gerado (que usa o SOAP 1.2, apesar de ter especificado o SOAP 1.1 com o WS Addressing 1.0) na SOAPUI e envio uma solicitação, o tipo de conteúdo é diferente e causa um erro. Presumo que isso ocorre porque, ao gerar o WSDL, ele usa o Soap 1.2, mas ao enviar uma solicitação, ele tenta usar o SOAP 1.1, mesmo que uma mensagem seja enviada usando o SOAP 1.2.
Existem alguns problemas relacionados:
Quando eu uso pela primeira vez<textMessageEncoding messageVersion="Soap11WSAddressing10" writeEncoding="utf-8" />
, adicione o WSDL ao SOAPUI, altere a codificação para o meu codificador personalizado e envie uma solicitação (o que resulta no WSDL sendo o Soap 1.1, então pensei que talvez fosse uma solução muito hacky), obtenho o seguinte erro, r:
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
está em maiúsculas e existe um espaço em branco após o;
. Eu acho que isso é bastante estranho e não deve ser um problema!No Visual Studio, o codificador personalizado possui uma linha ondulada que dizThe element 'binding' has invalid child element 'MissingWSAddressingHeadersTextEncoding'. List of possible elements expected: context, ....
Eu olheiesta postagem Stackoverflow e usou o editor da interface do usuário, mas a linha ondulada permanece. Eu também editei meuDotNetConfig.xsd
Estou 100% confiante de que o endereço está correto porque, em tempo de execução, o codificador personalizado funciona bem.
Por favor, dê uma olhada no meu código. Os links fornecidos no código são os que eu usei para criar o codificador.
A classe usada como extensãonamespace DigipoortConnector.Api.Digipoort_Services.Extensions
{
public class WSAddressingEncodingBindingElementExtension : BindingElementExtensionElement
{
public override Type BindingElementType => typeof(WSAddressingEncodingBindingElement);
protected override BindingElement CreateBindingElement()
{
return new WSAddressingEncodingBindingElement();
}
}
}
O elemento, fábrica e codificadornamespace 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);
}
}
}
}
A ligação e o elemento de extensão<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>
A única coisa que posso assumir que causa esse problema é que, em BUILD TIME (quando o WSDL será gerado?), Meu codificador personalizado NÃO será usado corretamente. Mas, em tempo de execução, ele será usado, mesmo que o codificador de fallback usado para gerar o WSDL (Textencoder com SOAP 1.2 padrão) esteja esperando 1.2 ...?
Tentei usar o editor da GUI do WCF (clique com o botão direito do mouse emweb.config
e selecioneEdit WCF configuration
) Quando o abro, ele diz que a DLL do meu codificador personalizado não pode ser encontrada. Posso ir em frente e adicioná-lo manualmente, mas salvar e reiniciar o editor produz o mesmo resultado. Ao inspecionar minha ligação personalizada e selecionar meu codificador personalizado, ele não mostra resultados:
Embora isso também ocorra porque minha classe de extensão de codificação não possui outras propriedades.
Estou totalmente perdido aqui! Por favor me ajude a descobrir isso!