У меня есть сервисная ссылка на сторонний API. Я использую собственный класс ChannelFactory для создания каналов ([WCF] типа System.ServiceModel.ClientBase) для этого API.
У меня есть собственный класс поведения (определенный ниже), который я присоединяю к этой конечной точке канала для обработки любых исключений, которые я получаю от API. В моем нормальном .NET-коде это работает нормально. Однако в Silverlight метод AfterReceiveReply вызывается только в том случае, если не было ошибки.
В этом случае вызывающий метод обнаруживает ошибку, когда вы пытаетесь сослаться на результат eventArgs: 'eventArgs.Result' threw an exception of type 'System.Reflection.TargetInvocationException'
.
Внутреннее исключение имеет: InnerException = {System.ServiceModel.CommunicationException: The remote server returned an error: NotFound.
И я вижу вышеупомянутую ошибку независимо от РЕАЛЬНОЙ ошибки. В Fiddler я вижу реальную ошибку, возвращающуюся. В обработке каналов есть что-то, что скрывает это. Ниже приведен пример ответа SOAP с реальной ошибкой. (Некоторые значения были удалены.)
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<soapenv:Fault>
<faultcode><!-- REMOVED REAL CODE --></faultcode>
<faultstring><!-- REMOVED REAL FAULT --></faultstring>
<detail>
<!-- REMOVED DETAILS -->
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
Я уверен, что я еще не предоставил достаточно информации об этом, но я не знаю, что все относится к делу. Запросите дополнительную информацию в комментариях.
Как можно отладить это? Тот же код работает в .NET, но Silverlight плохо с этим справляется.
Ниже приведен соответствующий код.
Поведение:
public class ExceptionMapperBehavior : IClientMessageInspector, IEndpointBehavior
{
public void AfterReceiveReply(ref Message reply, object correlationState)
{
//this is only called if there is no fault--not helpful!
if (reply == null || !reply.IsFault)
return;
//todo: make the exception pretty
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
//this is always called
return null;
}
}
Создание канала :
//...
var constructor = typeof(T).GetConstructor(new Type[] { typeof(Binding), typeof(EndpointAddress) });
var ret = (T)constructor.Invoke(new object[] { binding, endpointAddress });
ret.Endpoint.Behaviors.Add(new CredentialInserterEndpointBehavior(_authToken));
ret.Endpoint.Behaviors.Add(new ExceptionMapperBehavior());
return ret;