2009-03-04 5 views
1

Ich habe einen WCF-Client, der mit einer unbekannten Serverimplementierung kommuniziert, über die ich keine Kontrolle habe. Dieser Client funktioniert gut, es mag einfach nicht, wie es scheint, falsch geformte SOAP-Fehlermeldungen. Die Nachrichten, die ich erhalten wie folgt aussehen:Kann man schlecht geformte Fehlermeldungen konsumieren?

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

Ich glaube, nach der Seife Schema sollten die untergeordneten Elemente nicht wie qualifiziert und definiert werden, um zu sehen:

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

Gibt es etwas, das ich konfigurieren kann oder überschreiben, damit ich Nachrichten empfangen kann, die im letzteren Format ankommen, so dass ich die Fehlermeldungen anstelle von XML-Ausnahmen konsumieren kann?

Antwort

4

Ich bin nicht daran erinnern, wie ich stolperte über Nachrichten Inspektoren gefunden, aber, dass es, wie ich mein Problem gelöst.

This und this Artikel bereitgestellt, um die Basis des Inspektors für das Erstellen, und was folgt das Fleisch des Inspektors:

 
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

Es scheint, als ob die problematische Anwendung eine benutzerdefinierte (und schlecht implementierte) SOAP-Bibliothek verwendet. Der folgende Artikel könnte helfen (ich musste mich noch nicht damit befassen, da ich in einem reinen .Net-Shop bin).

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

+0

Vielleicht habe ich etwas verpasst, aber ich glaube, das ist alles Sachen, die ich für den Server tun können und nicht auf dem Client. Korrigieren Sie mich, wenn ich falsch liege, aber es schien, dass es eine IErrorHandler-Implementierung erstellen könnte, aber ich glaube, dass dies nur für die Serverseite gilt. – Dave

0

Beachten Sie, dass die System.Web.Services.Protocols.SoapHttpClientProtocol Klasse scheint deutlich toleranter gegenüber fehlerhaften Fehlerreaktionen als WCF.

Dies wird manchmal als ASMX-Dienstprotokoll bezeichnet. Dies könnte eine Option sein, die ebenfalls berücksichtigt werden muss.

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

Bitte geben Sie Ihrem Code zumindest eine Erläuterung. –

Verwandte Themen