Извлечение деталей из ответа WCF FaultException

Я успешно работаю со сторонним мыльным сервисом. Я добавил сервисную ссылку на мыльный веб-сервис, который автоматически генерирует классы.

При возникновении ошибки возвращается мыльный ответ, подобный следующему:

<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Client</faultcode>
         <faultstring xsi:type="xsd:string">Error while reading parameters of method 'Demo'</faultstring>
         <detail xsi:type="xsd:string">Invalid login or password. Connection denied.</detail>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Я могу поймать ошибку, но не извлечь детали. Я пробовал следующий код:

catch (FaultException ex)
{
    MessageFault msgFault = ex.CreateMessageFault();
    var elm = msgFault.GetDetail<string>();
    //throw Detail
}

Однако это ошибка со следующим узлом детализации не является объектом:

Expecting element 'string' from namespace 'http://schemas.datacontract.org/2004/07/MyDemoNamespace'.. Encountered 'Text'  with name '', namespace ''.

Это сторонний API, поэтому я не могу изменить ответ.

5 ответов

Решение

Предполагается, что подробный узел сообщения об ошибке содержит XML. GetDetail десериализует этот XML в заданный объект.

Поскольку содержимое не является XML, можно было использовать этот метод.

Однако вы можете получить доступ к XML и прочитать значение innerXml:

MessageFault msgFault = ex.CreateMessageFault();
var msg = msgFault.GetReaderAtDetailContents().Value;

Это подошло сработало.

Вот несколько методов, которые я нашел для извлечения подробной информации об исключении из FaultExceptions

Получение строкового содержимого одного элемента

catch (FaultException e)
{
    var errorElement = XElement.Parse(e.CreateMessageFault().GetReaderAtDetailContents().ReadOuterXml());
    var errorDictionary = errorElement.Elements().ToDictionary(key => key.Name.LocalName, val => val.Value);
    var errorMessage = errorDictionary?["ErrorMessage"];
}

Пример вывода:

Организации не существует.

Получите строковое содержимое всех деталей как одну строку

catch (FaultException e)
{
    var errorElement = XElement.Parse(e.CreateMessageFault().GetReaderAtDetailContents().ReadOuterXml());
    var errorDictionary = errorElement.Elements().ToDictionary(key => key.Name.LocalName, val => val.Value);
    var errorDetails = string.Join(";", errorDictionary);
}

Пример вывода:

[ErrorMessage, Организация не существует.];[EventCode, 3459046134826139648];[Параметры, ]

Получите строковое содержимое объекта Everything в виде строки XML

var errorElement = XElement.Parse(e.CreateMessageFault().GetReaderAtDetailContents().ReadOuterXml());
var xmlDetail = (string)errorElement;

Пример вывода:

<FaultData xmlns="http://schemas.datacontract.org/2004/07/Xata.Ignition.Common.Contract" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <ErrorMessage>Organization does not exist.</ErrorMessage>
    <EventCode>3459046134826139648</EventCode>
    <Parameters i:nil="true" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"></Parameters>
</FaultData>

Следующее должно дать вам значение элемента detail FaultException.

      var faultMessage = faultException.CreateMessageFault();
if(faultMessage.HasDetail){
  Console.Write(faultMessage.GetDetail<XElement>().Value);
}
   public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {

        if (reply.IsFault)
        {
            // Create a copy of the original reply to allow default WCF processing
            MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
            Message copy = buffer.CreateMessage();  // Create a copy to work with
            reply = buffer.CreateMessage();         // Restore the original message 

            MessageFault faultex = MessageFault.CreateFault(copy, Int32.MaxValue); //Get Fault from Message
            FaultCode codigo = faultex.Code;
            //if (faultex.HasDetail)... //More details

            buffer.Close(); 

Ты можешь поймать FaultException<TDetail>, который дает вам подробную информацию бесплатно.

catch (FaultException<string> ex)
{
    string yourDetail = ex.Detail;
}
Другие вопросы по тегам