FaultException. Деталь возвращается пустой
Я пытаюсь поймать данное исключение FaultException на клиенте WCF. Мне в основном нужно извлечь внутреннее описание из класса ошибок, чтобы затем я мог упаковать его в другое исключение, чтобы верхние уровни могли делать что угодно.
Я проделал это успешно несколько раз, но на этот раз он отличается тем, что ошибка объявляется как массив, как вы можете видеть из атрибута ссылки на службу, объявленного поверх метода, который выдает исключение:
[System.ServiceModel.FaultContractAttribute(typeof(FaultClass[]), Action = "http://whatever/", Name = "whateverBusinessFault")]
Это мой код:
try
{
// call service here
}
catch (FaultException<FaultClass[]> ex)
{
if (ex.Detail != null && ex.Detail.Length > 0)
{
throw new CustomException(ex.Detail[0].description);
}
else
{
throw;
}
}
Проблема в том, что Detail (который является массивом) всегда возвращается пустым в коде, даже если я вижу данные (поле описания и т. Д.) В ответе SOAP от трассировки WCF.
То, что мне нужно, определенно возвращается, но по какой-то причине либо не десериализовано, либо я не могу добраться до него из кода.
Любая помощь приветствуется!
ОБНОВЛЕНИЕ:
Попытка с предложением @Darin, но не повезло, строка, которую я извлекаю из XmlReader: "/r/n":
var sb = new StringBuilder();
using (XmlReader reader = fault.GetReaderAtDetailContents())
{
while (reader.Read())
sb.AppendLine(reader.ReadOuterXml());
}
var detail = sb.ToString();
Похоже, что подробный раздел вообще не подходит!
5 ответов
Я нашел решение на форуме UPS:
https://developerkitcommunity.ups.com/index.php/Special:AWCforum/st/id371
"Проблема заключалась в том, что Visual Studio не совсем правильно отобразила объекты ErrorDetail. Узел ErrorDetail называется" ErrorDetail ", но сгенерированный для него тип -"ErrorDetailType ". Я редактировал класс reference.cs, сгенерированный для каждой службы I. использовал и добавил TypeName:"
Трудно сказать, где проблема, но я подозреваю, что курящий пистолет - это веб-сервис этой оси, не генерирующий стандартное сообщение. Один из способов обойти это - самостоятельно проанализировать XML:
try
{
proxy.CallSomeMethod();
}
catch (FaultException ex)
{
var fault = ex.CreateMessageFault();
using (XmlReader reader = fault.GetReaderAtDetailContents())
{
// TODO: read the XML fault and extract the necessary information.
}
}
Мне понадобилось много времени, чтобы понять, как получить полное сообщение с FaultException
как строка В конце концов я понял это и написал этот метод расширения:
public static string GetDetail(this FaultException faultException)
{
if (faultException == null)
throw new ArgumentNullException(nameof(faultException));
MessageFault messageFault = faultException.CreateMessageFault();
if (messageFault.HasDetail) {
using (XmlDictionaryReader reader = messageFault.GetReaderAtDetailContents()) {
return reader.ReadContentAsString();
}
}
return null;
}
Первоначально я использовал reader.Value
но это появилось только в возвращении первой строки многострочного подробного сообщения. reader.ReadContentAsString()
Похоже, все получилось, включая новые строки, что я и хотел.
Я придумал самый простой тестовый пример, какой только мог. Я надеюсь, что это поможет вам. Сторона сервера:
[ServiceContract]
public interface IService1
{
[OperationContract]
[FaultContract(typeof(FaultClass[]))]
string Crash();
}
public class Service1 : IService1
{
public string Crash()
{
var exception = new FaultException<FaultClass[]>(new FaultClass[] { new FaultClass { Data = "TEST" } }, new FaultReason("Boom"));
throw exception;
}
}
[DataContract]
public class FaultClass
{
[DataMember]
public string Data { get; set; }
}
Сторона клиента:
try
{
using (var client = new Service1Client())
{
client.Crash();
}
}
catch(FaultException<FaultClass[]> e)
{
//Break here
}
У меня была похожая ситуация при попытке передать данные с ошибками (в частности, трассировка стека). Смотрите этот вопрос. В итоге я решил ее, создав собственную сериализуемую трассировку стека и включив ее в производный класс FaultException.