Pregunta

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

Para su información: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 "Mensaje" como puede ver a continuación.

Cuando se utiliza 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 parece correcto 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 está utilizando WCF, FaultException en el lado del cliente también imita la misma estructura, siendo falloException.Code.Name "Remitente" y falloException.Code.SubCode.Name siendo "MySubFaultCode".

Cuando se utiliza 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 parece correcto.Al observar las especificaciones de SOAP 1.1, esperaba ver que el "código de error" tuviera un valor de "s:Client.MySubFaultCode" cuando uso FaultCode.CreateSenderFaultCode(new FaultCode("MySubFaultCode")).Además, un cliente WCF obtiene una estructura incorrecta.El falloException.Code.Name es "MySubFaultCode" en lugar de ser "Remitente", y el falloException.Code.SubCode es nulo en lugar de que falloException.Code.SubCode.Name sea "MySubFaultCode".Además, failException.Code.IsSenderFault es falso.

Problema similar al utilizar FaultCode.CreateReceiverFaultCode(new FaultCode("MySubFaultCode")):

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

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

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

Error de conexión de Microsoft: 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?

¿Fue útil?

Solución

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://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);
        }
    }

Lamentablemente, no veo una manera de utilizar subcódigos sin dañar los clientes SOAP 1.1 o 1.2.

Si utiliza 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 de subcódigo adecuado en .NET (ya sea a través de los métodos estáticos de FaultCode o una de las sobrecargas), se rompe SOAP 1.1 pero funciona en SOAP 1.2.

Otros consejos

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 Soap 1.1 para códigos de falla personalizados:

(1) Usar la notación de "punto" como usted describe

(2) Definición de códigos de falla completamente nuevos

Desafortunadamente, se debe evitar la notación de "punto", ya que se desaconseja su uso en la especificación del perfil básico WS-I.Básicamente, esto significa que no existe un equivalente real del subcódigo de error de Soap 1.2 cuando se utiliza Soap 1.1.

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

Dado que "remitente" y "receptor" no son códigos de error válidos para Soap 1.1 y no existe un equivalente real de un subcódigo de error, no debe utilizar los métodos CreateSenderFaultCode y CreateReceiverFaultCode al generar códigos de error personalizados para Soap 1.1.

En su lugar, necesitarás definir tu propio código de falla, usando tu propio espacio de nombres y nombre:

FaultCode customFaultCode = nuevo FaultCode (nombre local, espacio de nombres de falla);

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top