Возможно ли использовать плохо сформированные сообщения об ошибках?

У меня есть клиент WCF, который обменивается данными с неизвестной реализацией сервера, над которой я не могу повлиять. Этот клиент работает нормально, ему просто не нравятся, казалось бы, неправильно сформированные сообщения об ошибках SOAP. Сообщения, которые я получаю, выглядят так:

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

Я считаю, что в соответствии со схемой мыла дочерние элементы не должны быть квалифицированы и должны выглядеть так:

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

Есть ли что-то, что я могу настроить или переопределить, чтобы я мог получать сообщения, которые поступают в последнем формате, чтобы я мог использовать сообщения об ошибках вместо исключений xml?


person Dave    schedule 04.03.2009    source источник


Ответы (3)


Я не могу вспомнить, как я наткнулся на Инспекторы сообщений, но это то, как я решил свою проблему.

This и эта статья предоставила основу для создания инспектора, а далее мясо инспектора:

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

person Dave    schedule 05.03.2009

Похоже, что приложение-нарушитель использует нестандартную (и плохо реализованную) библиотеку SOAP. Следующая статья может помочь (мне еще не приходилось иметь дело с этим, поскольку я нахожусь в чистом магазине .Net).

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

person Bill    schedule 04.03.2009
comment
Возможно, я что-то упустил, но я считаю, что это все, что я могу сделать для сервера, а не для клиента. Поправьте меня, если я ошибаюсь, но оказалось, что можно создать реализацию IErrorHandler, но я считаю, что это относится только к стороне сервера. - person Dave; 04.03.2009

Обратите внимание, что класс System.Web.Services.Protocols.SoapHttpClientProtocol кажется значительно более устойчивым к искаженным ответам Fault, чем WCF.

Иногда это называют протоколом служб ASMX. Это тоже может быть вариант для рассмотрения.

Говард Хоффман

person Howard Hoffman    schedule 06.04.2010