.NET WCF falhas geração incorrecta SOAP 1.1 faultcode valores
-
09-06-2019 - |
Pergunta
Eu estou a experimentar usando o FaultException e FaultException<T> para determinar o melhor padrão de uso em nossas aplicações.Precisamos de apoio WCF, bem como a não-serviço WCF consumidores/clientes, incluindo SOAP 1.1 e SOAP 1.2 clientes.
FYI:usando FaultExceptions com wsHttpBinding resultados em SOAP 1.2 semântica enquanto o uso de FaultExceptions com basicHttpBinding resultados em SOAP 1.1 semântica.
Eu estou usando o seguinte código para lançar um FaultException<FaultDetails>:
throw new FaultException<FaultDetails>(
new FaultDetails("Throwing FaultException<FaultDetails>."),
new FaultReason("Testing fault exceptions."),
FaultCode.CreateSenderFaultCode(new FaultCode("MySubFaultCode"))
);
O FaultDetails classe é apenas uma simples classe de teste que contém uma cadeia de propriedade de "Mensagem" como você pode ver abaixo.
Quando utilizar o wsHttpBinding a resposta é:
<?xml version="1.0" encoding="utf-16"?>
<Fault xmlns="http://www.w3.org/2003/05/soap-envelope">
<Code>
<Value>Sender</Value>
<Subcode>
<Value>MySubFaultCode</Value>
</Subcode>
</Code>
<Reason>
<Text xml:lang="en-US">Testing fault exceptions.</Text>
</Reason>
<Detail>
<FaultDetails xmlns="http://schemas.datacontract.org/2004/07/ClassLibrary" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Message>Throwing FaultException<FaultDetails>.</Message>
</FaultDetails>
</Detail>
Isso parece certo de acordo com o SOAP 1.2 especificações.Principal/de raiz "Código" é "Remetente", que tem um "Sub" de "MySubFaultCode".Se o consumidor de serviço/cliente está usando WCF o FaultException no lado do cliente também imita a mesma estrutura, com o faultException.Código.Nome ser "Remetente" e faultException.Código.O subcódigo.Nome ser "MySubFaultCode".
Quando utilizar basicHttpBinding a resposta é:
<?xml version="1.0" encoding="utf-16"?>
<s:Fault xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode>s:MySubFaultCode</faultcode>
<faultstring xml:lang="en-US">Testing fault exceptions.</faultstring>
<detail>
<FaultDetails xmlns="http://schemas.datacontract.org/2004/07/ClassLibrary" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Message>Throwing FaultException<FaultDetails>.</Message>
</FaultDetails>
</detail>
</s:Fault>
Isso não olhar para a direita.Olhando para o SOAP 1.1 especificações, eu estava esperando para ver o "faultcode" para ter um valor de "s:Client.MySubFaultCode" quando eu uso FaultCode.CreateSenderFaultCode(nova FaultCode("MySubFaultCode")).Também um cliente WCF recebe incorreta de uma estrutura.O faultException.Código.O nome é "MySubFaultCode" em vez de "Remetente", e o faultException.Código.O subcódigo é nulo em vez de faultException.Código.O subcódigo.Nome ser "MySubFaultCode".Além disso, o faultException.Código.IsSenderFault é falso.
Problema semelhante quando utilizar FaultCode.CreateReceiverFaultCode(nova FaultCode("MySubFaultCode")):
- funciona como esperado para SOAP 1.2
- gera "s:MySubFaultCode" em vez de "s:Server.MySubFaultCode" e o faultException.Código.IsReceiverFault é falso para SOAP 1.1
Este item também foi postado por alguém em http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=669420&SiteID=1 em 2006 e ninguém respondeu.Acho muito difícil acreditar que ninguém foi executado para isso, ainda.
Aqui está alguém a ter um problema semelhante: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3883110&SiteID=1&mode=1
Microsoft Connect erro: https://connect.microsoft.com/wcf/feedback/ViewFeedback.aspx?FeedbackID=367963
Descrição de como falhas deve funcionar: http://blogs.msdn.com/drnick/archive/2006/12/19/creating-faults-part-3.aspx
Estou fazendo algo errado ou é realmente um bug no WCF?
Solução
Esta é a minha solução actual:
/// <summary>
/// Replacement for the static methods on FaultCode to generate Sender and Receiver fault codes due
/// to what seems like bugs in the implementation for basicHttpBinding (SOAP 1.1). wsHttpBinding
/// (SOAP 1.2) seems to work just fine.
///
/// The subCode parameter for FaultCode.CreateReceiverFaultCode and FaultCode.CreateSenderFaultCode
/// seem to take over the main 'faultcode' value in the SOAP 1.1 response, whereas in SOAP 1.2 the
/// subCode is correctly put under the 'Code->SubCode->Value' value in the XML response.
///
/// This workaround is to create the FaultCode with Sender/Receiver (SOAP 1.2 terms, but gets
/// translated by WCF depending on the binding) and an agnostic namespace found by using reflector
/// on the FaultCode class. When that NS is passed in WCF seems to be able to generate the proper
/// response with SOAP 1.1 (Client/Server) and SOAP 1.2 (Sender/Receiver) fault codes automatically.
///
/// This means that it is not possible to create a FaultCode that works in both bindings with
/// subcodes.
/// </summary>
/// <remarks>
/// See http://stackoverflow.com/questions/65008/net-wcf-faults-generating-incorrect-soap-11-faultcode-values
/// for more details.
/// </remarks>
public static class FaultCodeFactory
{
private const string _ns = "http://schemas.microsoft.com/ws/2005/05/envelope/none";
/// <summary>
/// Creates a sender fault code.
/// </summary>
/// <returns>A FaultCode object.</returns>
/// <remarks>Does not support subcodes due to a WCF bug.</remarks>
public static FaultCode CreateSenderFaultCode()
{
return new FaultCode("Sender", _ns);
}
/// <summary>
/// Creates a receiver fault code.
/// </summary>
/// <returns>A FaultCode object.</returns>
/// <remarks>Does not support subcodes due to a WCF bug.</remarks>
public static FaultCode CreateReceiverFaultCode()
{
return new FaultCode("Receiver", _ns);
}
}
Infelizmente, eu não vejo uma maneira de usar subcódigos, sem interromper o SOAP 1.1 ou 1.2 clientes.
Se você usar o Código.O subcódigo de sintaxe, você pode criar SOAP 1.1 compatível faultcode valores, mas ele quebra SOAP 1.2.
Se você usar o bom subcódigo apoio .NET (através da estática FaultCode métodos ou uma das sobrecargas) quebra SOAP 1.1, mas funciona em SOAP 1.2.
Outras dicas
Resposta da Microsoft:
Como discutido em http://msdn.microsoft.com/en-us/library/ms789039.aspx, existem dois métodos descritos na especificação Soap 1.1 para os códigos de falha personalizadas:
(1) Usando a notação "ponto", como lhe chama,
(2) a Definição inteiramente novos códigos de falha
Infelizmente, a notação "ponto" deve ser evitado, uma vez que o uso é desencorajado em WS-I Basic Profile especificação.Essencialmente, isto significa que não há real equivalente a Soap 1.2 falha Subcódigo quando usando Soap 1.1.
Assim, ao gerar falhas, você terá que ter consciência de MessageVersion definido na ligação, e gerar faultcodes de acordo.
Desde o "emissor" e "receptor" não válido códigos de falha de Soap 1.1, e que não é equivalente a uma falha subcódigo, você não deve usar o CreateSenderFaultCode e CreateReceiverFaultCode métodos de geração de costume códigos de falha de Soap 1.1.
Em vez disso, você precisará definir o seu próprio faultcode, usando o seu próprio espaço de nomes e o nome:
FaultCode customFaultCode = new FaultCode(nome local, faultNamespace);