2009-03-04 16 views
1

J'ai un client WCF communiquant avec une implémentation de serveur inconnue sur laquelle je n'ai aucun contrôle. Ce client fonctionne correctement, il n'aime pas, ce qui semble être, des messages SOAP Fault mal formés. Les messages que je reçois ressemblent:Possible de consommer des messages d'erreur mal formés?

 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
    <soap:Header>...</soap:Header> 
    <soap:Body> 
     <soap:Fault> 
      <soap:faultcode>soap:Client</soap:faultcode> 
      <soap:faultstring>...</soap:faultstring> 
      <soap:detail>...</soap:detail> 
     </soap:Fault> 
    </soap:Body> 
</soap:Envelope> 

Je crois selon le schéma de savon les éléments enfants ne doivent pas être qualifiés et nis pour ressembler à:

 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
    <soap:Header>...</soap:Header> 
    <soap:Body> 
     <soap:Fault> 
      <faultcode>soap:Client</faultcode> 
      <faultstring>...</faultstring> 
      <detail>...</detail> 
     </soap:Fault> 
    </soap:Body> 
</soap:Envelope> 

Y at-il quelque chose que je peux configurer ou override afin que je puisse consommer des messages qui arrivent dans ce dernier format afin que je puisse consommer les messages d'erreur au lieu des exceptions xml?

Répondre

4

Je suis ne me souviens pas comment j'ai trouvé trébuché à travers les inspecteurs de message, mais que ce que je résolu mon problème.

This et this article a fourni la base pour la création de l'inspecteur, et ce qui suit est la viande de l'inspecteur:

 
public void AfterReceiveReply(ref Message reply, object correlationState) 
{ 
    if (!reply.IsFault) 
     return; 

    var document = new XmlDocument(); 

    document.Load(reply.GetReaderAtBodyContents()); 

    var navigator = document.CreateNavigator(); 
    var manager = new XmlNamespaceManager(navigator.NameTable); 

    manager.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/"); 

    var it = navigator.Select("//soap:Fault", manager); 

    if (it.MoveNext() && it.Current.HasChildren && it.Current.MoveToChild(XPathNodeType.Element)) 
    { 
     do 
     { 
      var c = it.Current; 

      if (string.IsNullOrEmpty(c.Prefix)) 
       continue; 

      c.ReplaceSelf("<" + c.LocalName + ">" + c.InnerXml + "</" + c.LocalName + ">"); 

      /// we may want to record the detail included inside the detail element, 
      /// it is not reported in the FaultException that is raised. 

     } while (it.Current.MoveToNext()); 
    } 

    var reader = XmlDictionaryReader.CreateDictionaryReader(new XmlNodeReader(document)); 

    reader.MoveToStartElement(); 

    var fixedReply = Message.CreateMessage(reply.Version, null, reader); 

    fixedReply.Headers.CopyHeadersFrom(reply.Headers); 
    fixedReply.Properties.CopyProperties(reply.Properties); 

    reply = fixedReply; 
} 

0

Il semble que l'application fautive utilise une bibliothèque SOAP personnalisée (et mal implémentée). L'article suivant pourrait aider (je n'ai pas eu à faire face à ceci pour autant que je suis dans un magasin .Net pur).

http://msdn.microsoft.com/en-us/library/ms733721.aspx

+0

Peut-être que je l'ai raté quelque chose, mais je crois que tout cela est des choses que je peux faire pour le serveur et non le client. Corrigez-moi si je me trompe mais il est apparu que cela pourrait créer une implémentation de IErrorHandler, mais je crois que cela ne s'applique qu'au côté serveur. – Dave

0

Notez que la classe System.Web.Services.Protocols.SoapHttpClientProtocol semble considérablement plus tolérant des réponses Fault malformées que WCF.

Ceci est parfois appelé protocole de services ASMX. Cela peut être une option à considérer aussi.

Howard Hoffman

0
} catch (SoapFaultClientException e) { 
    log.error(e); 
    SoapFaultDetail soapFaultDetail = e.getSoapFault().getFaultDetail(); 
    SoapFaultDetailElement detailElementChild = (SoapFaultDetailElement) soapFaultDetail.getDetailEntries().next(); 
    Source detailSource = detailElementChild.getSource(); 

    try { 
     Object detail = (JAXBElement<SearchResponse>) getWebServiceTemplate().getUnmarshaller().unmarshal(detailSource); 
//    throw new SoapFaultWithDetailException(detail); 

    } catch (IOException e1) { 
     throw new IllegalArgumentException("cannot unmarshal SOAP fault detail object: " + soapFaultDetail.getSource()); 
    } 

} 
+0

S'il vous plaît au moins quelques explications à votre code. –