WCF CommunicationException без подробностей сообщения об исключении
Одна из вещей, которые я никогда не понимал в WCF, заключается в том, что подробности сообщения об исключении не передаются обратно вызывающему клиенту, когда сервер встречает необработанное исключение.
Например, если у меня есть следующий код сервера
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class Server : IServer
{
public DTO GetDTO()
{
DTO dto = new DTO();
dto.dto = dto;
return dto;
}
}
public class DTO
{
public DTO dto;
}
[ServiceContract]
public interface IServer
{
[OperationContract]
DTO GetDTO();
}
Я специально ввел ObjectGraph, чтобы вызвать исключение сериализации при возврате объекта DTO.
Если у меня есть клиент, который вызывает этот сервер GetDTO()
метод, я получу следующее CommunicationException
,
Разъем подключения был прерван. Это может быть вызвано ошибкой обработки вашего сообщения или превышением тайм-аута приема удаленным хостом, или проблемой основного сетевого ресурса. Тайм-аут локального сокета был '00:00:58.9350000'.
Что абсолютно бесполезно. У него нет внутреннего исключения и даже реального сообщения об исключении.
Если затем вы используете Microsoft Service TraceViewer, вы увидите исключение, но для этого необходимо включить трассировку диагностики.
Сообщение об исключении, которое должно быть отправлено обратно:
Произошла ошибка при попытке сериализации параметра http://tempuri.org/:GetDTOResult. Сообщение InnerException было "Граф объекта для типа" TestWCFLib.DTO "содержит циклы и не может быть сериализовано, если отслеживание ссылок отключено.". Пожалуйста, смотрите InnerException для более подробной информации.
Кто-нибудь может сказать мне, как получить правильное сообщение об исключении на стороне клиента? Очевидно, что установка IncludeExceptionDetailInFaults
правда не имеет значения.
1 ответ
Я думаю, что именно из-за того, что ошибки сервера не распространяются на клиента. В целом, это практика, которая заключается в том, чтобы не раскрывать внутренние компоненты сервера клиентам, так как основная цель архитектуры Client Server - независимость от сервера.
Вы все еще можете достичь этого с помощью Fault Exception
Украсьте свою сервисную декларацию договором о неисправности
[ServiceContract]
public interface IServer
{
[OperationContract]
[FaultContract(typeof(MyApplicationFault))]
DTO GetDTO();
}
Затем перехватите ошибки в реализации servcie и сгенерируйте исключение ошибки.
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class Server : IServer
{
public DTO GetDTO()
{
try
{
DTO dto = new DTO();
dto.dto = dto;
return dto;
}
catch (Exception ex)
{
MyApplicationFault fault = new MyApplicationFault(...);
throw new FaultException<MyApplicationFault>(fault);
}
}
}
И лови исключение в клиенте
IServer proxy = ...; //Get proxy from somewhere
try
{
proxy.GetDTO();
}
catch (TimeoutException) { ... }
catch (FaultException<MyApplicationFault> myFault) {
MyApplicationFault detail = myFault.Detail;
//Do something with the actual fault
}
catch (FaultException otherFault) { ... }
catch (CommunicationException) { ... }
Надеюсь это поможет. Для хорошего учебника, пожалуйста, смотрите Учебное пособие по проекту кода на исключение ошибок