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) { ... }

Надеюсь это поможет. Для хорошего учебника, пожалуйста, смотрите Учебное пособие по проекту кода на исключение ошибок

Другие вопросы по тегам