Domanda

Sto sperimentando l'utilizzo di FaultException e FaultException<T> per determinare il miglior modello di utilizzo nelle nostre applicazioni.È necessario supportare i consumatori/clienti dei servizi WCF e non WCF, inclusi i client SOAP 1.1 e SOAP 1.2.

PER TUA INFORMAZIONE:l'uso di FaultException con wsHttpBinding produce la semantica SOAP 1.2 mentre l'uso di FaultException con basicHttpBinding produce la semantica SOAP 1.1.

Sto utilizzando il seguente codice per lanciare una FaultException<FaultDetails>:

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

La classe FaultDetails è solo una semplice classe di test che contiene una proprietà "Message" di stringa, come puoi vedere di seguito.

Quando si utilizza wsHttpBinding la risposta è:

<?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>

Questo sembra corretto secondo le specifiche SOAP 1.2.Il "Codice" principale/radice è "Sender", che ha un "Sottocodice" di "MySubFaultCode".Se il consumatore/cliente del servizio utilizza WCF, anche la FaultException sul lato client imita la stessa struttura, con faultException.Code.Name che è "Sender" e faultException.Code.SubCode.Name è "MySubFaultCode".

Quando si utilizza basicHttpBinding la risposta è:

<?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>

Questo non sembra giusto.Osservando le specifiche SOAP 1.1, mi aspettavo di vedere il "faultcode" con un valore di "s:Client.MySubFaultCode" quando utilizzo FaultCode.CreateSenderFaultCode(new FaultCode("MySubFaultCode")).Anche un client WCF ottiene una struttura errata.FaultException.Code.Name è "MySubFaultCode" invece di "Sender" e FaultException.Code.SubCode è null invece di FaultException.Code.SubCode.Name è "MySubFaultCode".Inoltre, faultException.Code.IsSenderFault è falso.

Problema simile quando si utilizza FaultCode.CreateReceiverFaultCode(new FaultCode("MySubFaultCode")):

  • funziona come previsto per SOAP 1.2
  • genera "s:MySubFaultCode" invece di "s:Server.MySubFaultCode" e faultException.Code.IsReceiverFault è falso per SOAP 1.1

Questo articolo è stato pubblicato anche da qualcun altro su http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=669420&SiteID=1 nel 2006 e nessuno ha risposto.Trovo molto difficile credere che nessuno si sia ancora imbattuto in questo.

Ecco qualcun altro che ha un problema simile: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3883110&SiteID=1&mode=1

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

Descrizione di come dovrebbero funzionare gli errori: http://blogs.msdn.com/drnick/archive/2006/12/19/creating-faults-part-3.aspx

Sto facendo qualcosa di sbagliato o è davvero un bug in WCF?

È stato utile?

Soluzione

Questa è la mia soluzione attuale:

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

Purtroppo non vedo un modo per utilizzare i sottocodici senza interrompere i client SOAP 1.1 o 1.2.

Se si utilizza la sintassi Code.SubCode, è possibile creare valori di codici di errore compatibili con SOAP 1.1, ma ciò interrompe SOAP 1.2.

Se si utilizza il supporto del sottocodice appropriato in .NET (tramite i metodi statici FaultCode o uno degli sovraccarichi), si interrompe SOAP 1.1 ma funziona in SOAP 1.2.

Altri suggerimenti

Risposta di Microsoft:

Come discusso in http://msdn.microsoft.com/en-us/library/ms789039.aspx, esistono due metodi delineati nella specifica Soap 1.1 per i codici di errore personalizzati:

(1) Utilizzando la notazione "punto" come descrivi

(2) Definizione di codici di errore completamente nuovi

Sfortunatamente, la notazione "punto" dovrebbe essere evitata, poiché il suo utilizzo è sconsigliato nella specifica del profilo base WS-I.In sostanza, ciò significa che non esiste un reale equivalente del sottocodice di errore di Soap 1.2 quando si utilizza Soap 1.1.

Pertanto, quando generi errori, dovrai essere consapevole della MessageVersion definita nell'associazione e generare codici di errore di conseguenza.

Poiché "mittente" e "destinatario" non sono codici di errore validi per Soap 1.1 e non esiste un equivalente reale di un sottocodice di errore, non dovresti utilizzare i metodi CreateSenderFaultCode e CreateReceiverFaultCode quando generi codici di errore personalizzati per Soap 1.1.

Dovrai invece definire il tuo codice di errore, utilizzando il tuo spazio dei nomi e il tuo nome:

FaultCode customFaultCode = nuovo FaultCode(localName, guastoNamespace);

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top