2008-09-15 6 views
9

J'expérimente l'utilisation de FaultException et FaultException <T> pour déterminer le meilleur modèle d'utilisation dans nos applications. Nous devons prendre en charge WCF ainsi que les clients/clients de services non-WCF, y compris les clients SOAP 1.1 et SOAP 1.2. FYI: l'utilisation de FaultExceptions avec wsHttpBinding aboutit à une sémantique SOAP 1.2 alors que l'utilisation de FaultExceptions avec basicHttpBinding entraîne une sémantique SOAP 1.1.Erreurs WCF .NET générant des valeurs de code d'erreur SOAP 1.1 incorrectes

J'utilise le code suivant pour lancer une FaultException <FaultDetails>:

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

La classe FaultDetails est juste une classe de test simple qui contient une chaîne propriété « message » que vous pouvez voir ci-dessous.

Lorsque vous utilisez WSHttpBinding la réponse est:

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

Cela ressemble à droite selon le SOAP 1.2 spécifications. Le "code" principal/racine est "Sender", qui a un "Subcode" de "MySubFaultCode". Si le consommateur de service/client utilise WCF, la FaultException du côté client imite également la même structure, avec la propriété faultException.Code.Name étant "Sender" et faultException.Code.SubCode.Name étant "MySubFaultCode".

Lorsque vous utilisez BasicHttpBinding la réponse est:

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

Cela ne semble pas juste. En regardant les spécifications SOAP 1.1, je m'attendais à voir le "faultcode" avoir une valeur de "s: Client.MySubFaultCode" quand j'utilise FaultCode.CreateSenderFaultCode (new FaultCode ("MySubFaultCode")). Un client WCF obtient également une structure incorrecte. Le fichier faultException.Code.Name est "MySubFaultCode" au lieu d'être "Sender", et le fichier faultException.Code.SubCode est nul au lieu de faultException.Code.SubCode.Name étant "MySubFaultCode". En outre, le faultException.Code.IsSenderFault est faux.

problème similaire lors de l'utilisation FaultCode.CreateReceiverFaultCode (nouvelle FaultCode ("MySubFaultCode")):

  • fonctionne comme prévu pour SOAP 1.2
  • génère « s: MySubFaultCode » au lieu de « s: Server.MySubFaultCode » et le faultException.Code.IsReceiverFault est faux pour SOAP 1,1

Cet article a également été publié par quelqu'un d'autre sur http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=669420&SiteID=1 en 2006 et personne n'a répondu. Je trouve très difficile de croire que personne n'a encore été confronté à cela.

Voici quelqu'un qui a encore un problème similaire: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3883110&SiteID=1&mode=1

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

Description de la façon des défauts devraient fonctionner: http://blogs.msdn.com/drnick/archive/2006/12/19/creating-faults-part-3.aspx

que je fais quelque chose de mal ou est-ce vraiment un bug en WCF?

Répondre

8

Voici ma solution actuelle:

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

Malheureusement je ne vois pas un moyen d'utiliser des sous-codes sans casser soit SOAP 1.1 ou 1.2 clients. Si vous utilisez la syntaxe Code.SubCode, vous pouvez créer des valeurs de code d'erreur compatibles avec SOAP 1.1 mais cela interrompt SOAP 1.2.

Si vous utilisez le support de sous-code approprié dans .NET (soit via les méthodes FaultCode statiques ou l'une des surcharges), il rompt SOAP 1.1 mais fonctionne dans SOAP 1.2.

7

Réponse de Microsoft:

Comme indiqué dans http://msdn.microsoft.com/en-us/library/ms789039.aspx, il y a deux méthodes décrites dans le Soap 1.1 spécification pour les codes de défaut personnalisés:

(1) En utilisant la notation "point" que vous décrivez

(2) Définition entièrement nouveaux codes de défaut

Malheureusement, la notation « point » doit être évité, car il est utilisation est déconseillée dans la spécification du profil WS-I Basic. Essentiellement, cela signifie qu'il n'y a pas d'équivalent réel du sous-code de faute Soap 1.2 lors de l'utilisation de Soap 1.1. Ainsi, lors de la génération de fautes, vous devez connaître le MessageVersion défini dans la liaison et générer des codes de défaut en conséquence. Comme "expéditeur" et "destinataire" ne sont pas des codes de défaut valides pour Soap 1.1, et qu'il n'y a pas d'équivalent réel d'un sous-code, vous ne devez pas utiliser les méthodes CreateSenderFaultCode et CreateReceiverFaultCode lors de la génération de codes d'erreur personnalisés pour Soap 1.1 .

Au lieu de cela, vous devrez définir votre propre faultcode, en utilisant votre propre espace de noms et le nom:

FaultCode customFaultCode = new FaultCode (localName, faultNamespace);

Questions connexes