visual studio services net example entre diferencia crear .net wcf web-services soap

.net - services - web service c# visual studio 2017



Las fallas.NET WCF generan valores incorrectos de código de error SOAP 1.1 (2)

Estoy experimentando con el uso de FaultException y FaultException <T> para determinar el mejor patrón de uso en nuestras aplicaciones. Necesitamos apoyar a WCF así como a consumidores / clientes que no pertenecen a WCF, incluidos los clientes SOAP 1.1 y SOAP 1.2.

FYI: el uso de FaultExceptions con wsHttpBinding da como resultado la semántica de SOAP 1.2, mientras que el uso de FaultExceptions con basicHttpBinding da como resultado la semántica de SOAP 1.1.

Estoy usando el siguiente código para lanzar una FaultException <FaultDetails>:

throw new FaultException<FaultDetails>( new FaultDetails("Throwing FaultException<FaultDetails>."), new FaultReason("Testing fault exceptions."), FaultCode.CreateSenderFaultCode(new FaultCode("MySubFaultCode")) );

La clase FaultDetails es simplemente una clase de prueba simple que contiene una propiedad de cadena de "Mensaje" como puede ver a continuación.

Al usar wsHttpBinding, la respuesta es:

<?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&lt;FaultDetails&gt;.</Message> </FaultDetails> </Detail>

Esto se ve bien según las especificaciones de SOAP 1.2. El "Código" principal / raíz es "Remitente", que tiene un "Subcódigo" de "MySubFaultCode". Si el consumidor / cliente del servicio utiliza WCF, FaultException en el lado del cliente también imita la misma estructura, con faultException.Code.Name como "Sender" y faultException.Code.SubCode.Name como "MySubFaultCode".

Al usar basicHttpBinding, la respuesta es:

<?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&lt;FaultDetails&gt;.</Message> </FaultDetails> </detail> </s:Fault>

Esto no se ve bien. En cuanto a las especificaciones de SOAP 1.1, esperaba ver el "código de falla" para tener un valor de "s: Client.MySubFaultCode" cuando uso FaultCode.CreateSenderFaultCode (new FaultCode ("MySubFaultCode")). También un cliente WCF obtiene una estructura incorrecta. El faultException.Code.Name es "MySubFaultCode" en lugar de ser "Sender", y el faultException.Code.SubCode es nulo en lugar de faultException.Code.SubCode.Name que es "MySubFaultCode". Además, faultException.Code.IsSenderFault es falso.

Problema similar cuando se utiliza FaultCode.CreateReceiverFaultCode (new FaultCode ("MySubFaultCode")):

  • funciona como se esperaba para SOAP 1.2
  • genera "s: MySubFaultCode" en lugar de "s: Server.MySubFaultCode" y faultException.Code.IsReceiverFault es falso para SOAP 1.1

Este elemento también fue publicado por otra persona en http://forums.microsoft.com/MSDN/ShowPost.aspx?PIDID=669420&SiteID=1 en 2006 y nadie lo ha respondido. Me resulta muy difícil creer que nadie se ha encontrado con esto, todavía.

Aquí hay otra persona que tiene un problema similar: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3883110&SiteID=1&mode=1

Error de Microsoft Connect: https://connect.microsoft.com/wcf/feedback/ViewFeedback.aspx?FeedbackID=367963

Descripción de cómo deberían funcionar las fallas: http://blogs.msdn.com/drnick/archive/2006/12/19/creating-faults-part-3.aspx

¿Estoy haciendo algo mal o es realmente un error en WCF?


Esta es mi solución 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://.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); } }

Lamentablemente, no veo una forma de usar subcódigos sin romper SOAP 1.1 o 1.2 clientes.

Si usa la sintaxis Code.SubCode, puede crear valores de código de error compatibles con SOAP 1.1 pero rompe SOAP 1.2.

Si utiliza el soporte adecuado de subcódigo en .NET (ya sea a través de los métodos estáticos FaultCode o una de las sobrecargas) rompe SOAP 1.1 pero funciona en SOAP 1.2.


Respuesta de Microsoft:

Como se discutió en http://msdn.microsoft.com/en-us/library/ms789039.aspx , hay dos métodos descritos en la especificación de Soap 1.1 para códigos de falla personalizados:

(1) Usando la notación "punto" como describes

(2) Definir códigos de falla completamente nuevos

Desafortunadamente, se debe evitar la notación "punto", ya que su uso se desaconseja en la especificación WS-I Basic Profile. Básicamente, esto significa que no hay un equivalente real del SubCode de fallas de Soap 1.2 al usar Soap 1.1.

Por lo tanto, al generar fallas, deberá conocer la MessageVersion definida en el enlace y generar códigos de falla en consecuencia.

Dado que "emisor" y "receptor" no son códigos de falla para Soap 1.1, y no existe un equivalente real de un subcódigo de falla, no debe usar los métodos CreateSenderFaultCode y CreateReceiverFaultCode al generar códigos de falla personalizados para Soap 1.1.

En cambio, deberá definir su propio código de falla, utilizando su propio espacio de nombre y nombre:

FaultCode customFaultCode = new FaultCode (localName, faultNamespace);