2013-06-13 19 views
6

Sto tentando di aggiungere ulteriori informazioni su un errore SOAP in un'applicazione client open source. Il client è configurato per chiamare "HandleFault" ogni volta che incontra un errore SOAP. Il metodo maniglia Fault è la seguente:Come gestire Eccezione errore WCF

public static void HandleFault(Message message) { 
     MessageFault fault = MessageFault.CreateFault(message, Int32.MaxValue); 
     throw System.ServiceModel.FaultException.CreateFault(fault, 
      typeof(PermissionDeniedFault), 
      typeof(EndpointUnavailable), 
      typeof(InvalidRepresentation), 
      typeof(UnwillingToPerformFault), 
      typeof(CannotProcessFilter), 
      typeof(AnonymousInteractionRequiredFault) 
     ); 
    } 

Ecco una porzione di errore SOAP che viene passato come "messaggio" quando cerco di fare qualcosa di simile cambiamento di un numero di telefono per formato non valido dal client.

<s:Body u:Id="_2"> 
<Fault xmlns="http://www.w3.org/2003/05/soap-envelope"> 
    <Code> 
    <Value>Sender</Value> 
    <Subcode> 
     <Value xmlns:a="http://schemas.xmlsoap.org/ws/2004/09/transfer">a:InvalidRepresentation</Value> 
    </Subcode> 
    </Code> 
    <Reason> 
    <Text xml:lang="en-US">The request message contains errors that prevent processing the request.</Text> 
    </Reason> 
    <Detail> 
    <RepresentationFailures xmlns="http://schemas.microsoft.com/2006/11/ResourceManagement" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
     <AttributeRepresentationFailure> 
     <AttributeType>OfficePhone</AttributeType> 
     <AttributeValue>(123)456-7890</AttributeValue> 
     <AttributeFailureCode>ValueViolatesRegularExpression</AttributeFailureCode> 
     <AdditionalTextDetails>The specified attribute value does not satisfy the regular expression.</AdditionalTextDetails> 
     </AttributeRepresentationFailure> 
     <CorrelationId>11042dda-3ce9-4563-b59e-d1c1355819a4</CorrelationId> 
    </RepresentationFailures> 
    </Detail> 
</Fault> 

Ogni volta che viene rilevato che Fault, il client restituisce solo indietro "Il messaggio di richiesta contiene errori che impediscono l'elaborazione della richiesta.", Mi piacerebbe includere il "AttributeRepresentationFailure" nodo e bambino nodi prima di ripetere l'eccezione nel client.

Il modo in cui ho capito è che ho bisogno di definire una classe Fault che contenga quei dettagli da desertificare, in modo che la chiamata a "CreateFault" possa restituire a. Ho letto http://msdn.microsoft.com/en-us/library/ms733841.aspx ma non capisco esattamente come definire la classe in modo che il client sappia quale tipo di errore viene generato.

UPDATE

Nel metodo colpa maniglia lato client ho aggiunto

try 
     { 
      throw faultexcept; 
     } 
     catch (System.ServiceModel.FaultException<InvalidRepresentation> invalidRepresentationFault) 
     { 
      throw invalidRepresentationFault; 
     } 
     catch (System.ServiceModel.FaultException otherFault) 
     { 
      throw otherFault; 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 

La colpa è sempre catturato sotto la classe colpa base "otherFault". La mia classe InvalidRepresentation è definito come di seguito

[DataContract(Namespace = Constants.Rm.Namespace)] 
public class InvalidRepresentation 
{ 
    private string _attributeType; 
    private string _attributeValue; 
    private string _attributeFailureCode; 
    private string _additionalTextDetails; 

    [DataMember] 
    public string AttributeType 
    { 
     get { return _attributeType; } 
     set { _attributeType = value; } 
    } 

    [DataMember] 
    public string AttributeValue 
    { 
     get { return _attributeValue; } 
     set { _attributeValue = value; } 
    } 

    [DataMember] 
    public string AttributeFailureCode 
    { 
     get { return _attributeFailureCode; } 
     set { _attributeFailureCode = value; } 
    } 

    [DataMember] 
    public string AdditionalTextDetails 
    { 
     get { return _additionalTextDetails; } 
     set { _additionalTextDetails = value; } 
    } 


    public InvalidRepresentation() { 

    } 
} 

risposta

1

sto usando l'esempio di matematica dall'articolo lei ha fatto riferimento a. Crea la classe di errore:

[DataContract(Namespace="http://Microsoft.ServiceModel.Samples")] 
public class MathFault 
{  
... 
} 

Decora il tuo metodo con OperationContract, ad es.

[OperationContract] 
[FaultContract(typeof(MathFault))] 
int Divide(int n1, int n2); 

Crea il tuo oggetto MathFault con dati sensibili. Avvolgilo e gettalo:

throw new FaultException<MathFault>(yourFault); 

Spero che questo aiuti.

+0

grazie! Penso di essere sulla strada giusta, ma quando definisco la mia classe Fault, che aspetto ha questa classe per gestire correttamente l'errore nell'esempio che ho inviato sopra? Inoltre, in che modo nel codice client determino quale errore è stato generato, presumo che sia stato preso in considerazione nel codice 'System.ServiceModel.FaultException.CreateFault'? –

3

Per aggiungere alla risposta di Fredrik, la classe di errore può essere qualsiasi cosa sia necessaria per trasmettere i dettagli del proprio errore personalizzato al client. Non deve ereditare da un'altra classe o implementare un'interfaccia. Deve solo essere contrassegnato con l'attributo DataContract.

Per quanto riguarda la cattura sul lato client:

try 
{ 
    ... 
} 
catch (FaultException<MathFault> mathFault) 
{ 
    // handle a math fault 
} 
catch (FaultException<OtherCustomFault> otherFault) 
{ 
    // handle another type of custom fault 
} 
catch (Exception ex) 
{ 
    // regular exception handling 
} 
+0

Grazie a @Jason, ma il mio errore non viene mai rilevato come una rappresentazione non valida. Viene sempre rilevato come FaultException generico. Ho definito DataContract nella mia classe InvalidRepresentation. Non capisco come si sa che tipo di errore viene lanciato ?? –

+0

Dal lato del servizio, stai gettando l'errore nel modo in cui Fredrik ha descritto di seguito? 'Gira nuova FaultException (yourFault);' – Jason

2

sono stato finalmente in grado di trovare una soluzione a questo, grazie a tutti coloro che hanno contribuito! Questa non è la soluzione migliore e deve essere ripulita, ma funziona finché non imparo di più sugli errori WCF e SOAP. Inoltre, non ho accesso al codice del servizio, solo il codice client. Il codice client viene eseguito come modulo di PowerShell.

InvalidRepresentationFault Classe

using System.Runtime.Serialization; 
namespace Client.Faults { 
    public class InvalidRepresentationFault 
    { 
     public InvalidRepresentationFault() {} 
    } 
    [DataContract(Namespace = Constants.Rm.Namespace)] 
    public class RepresentationFailures 
    { 
     [DataMember()] 
     public FailureDetail AttributeRepresentationFailure; 

    [DataContract(Namespace = Constants.Rm.Namespace)] 
    public class FailureDetail 
    { 
     [DataMember(Order = 1)] 
     public string AttributeType; 

     [DataMember(Order = 2)] 
     public string AttributeValue; 

     [DataMember(Order = 3)] 
     public string AttributeFailureCode; 

     [DataMember(Order = 4)] 
     public string AdditionalTextDetails; 
    } 

    [DataMember] 
    public string CorrelationId; 
} 

}

Codice Cliente HandleFault

public static void HandleFault(Message message) { 
     MessageFault fault = MessageFault.CreateFault(message, Int32.MaxValue); 

     //Let the fault exception choose the best fault to handle? 
     System.ServiceModel.FaultException faultexcept = System.ServiceModel.FaultException.CreateFault(fault, 
      typeof(PermissionDeniedFault), 
      typeof(AuthenticationRequiredFault), 
      typeof(AuthorizationRequiredFault), 
      typeof(EndpointUnavailable), 
      typeof(FragmentDialectNotSupported), 
      typeof(InvalidRepresentationFault), 
      typeof(UnwillingToPerformFault), 
      typeof(CannotProcessFilter), 
      typeof(FilterDialectRequestedUnavailable), 
      typeof(UnsupportedExpiration), 
      typeof(AnonymousInteractionRequiredFault), 
      typeof(RepresentationFailures) 
     ); 

     try 
     { 
      throw faultexcept; 
     } 
     catch (System.ServiceModel.FaultException<RepresentationFailures> invalidRepresentationFault) 
     { 
      throw new Exception(
       String.Format(
        "{0}\r\nfor Attribute \"{1}\" with Value \"{2}\"", 
         invalidRepresentationFault.Detail.AttributeRepresentationFailure.AdditionalTextDetails, 
         invalidRepresentationFault.Detail.AttributeRepresentationFailure.AttributeType, 
         invalidRepresentationFault.Detail.AttributeRepresentationFailure.AttributeValue 
        ), 
       invalidRepresentationFault 
      ); 
     } 
     catch (System.ServiceModel.FaultException otherFault) 
     { 
      throw otherFault; 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

Ora, quando il servizio getta un errore SOAP si ottiene deserializzato nella classe "RepresentationFailures", che posso personalizzare prima di ricominciare a monte (in questo caso a powershell)

+0

buon pattern mapping ** FaultException ** a ** Exception **? – Kiquenet

+0

Non lanciare Eccezione. Crea la tua eccezione personalizzata e passa ciò di cui hai bisogno. – nashwan