Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Silverlight not call AfterReceiveReply for my custom ServiceModel.ClientBase<TChannel> channel's behavior?

I have a service reference to a third-party API. I use a custom ChannelFactory class to build channels ([WCF] of type System.ServiceModel.ClientBase) to this API.

I have a custom behavior class (defined below) that I attach to this channel endpoint in order to handle any exceptions that I get back from the API. In my normal .NET code, this works fine. In Silverlight, however, the AfterReceiveReply method is only called if there was NO error.

In this case, the calling method encounters an error when you try to reference the result of the eventArgs: 'eventArgs.Result' threw an exception of type 'System.Reflection.TargetInvocationException'.

The inner exception has: InnerException = {System.ServiceModel.CommunicationException: The remote server returned an error: NotFound.

And I see the above error regardless of the REAL error. In Fiddler, I can see the real error coming back. There is just something about the channel processing that hides it. Below is an example of the SOAP response that has the real error. (Some values were removed.)

<?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>

I'm sure that I haven't provided enough information about this yet, but I don't know what all is relevant. Ask for more info in the comments.

How can I go about debugging this? The same code works in .NET, but Silverlight doesn't handle it well.

Some relevant code is below.

Behavior:

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;
    }
}

Channel Creation:

//...
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;
like image 373
EndangeredMassa Avatar asked Feb 05 '11 02:02

EndangeredMassa


1 Answers

Don't know if this helps/uses something.

By default silverlight performs HTTP-Requests (include SOAP/REST) through the browser. With these calls all HTTP/HTTPS requests will handled by silverlight-client network stack.

bool httpResult = WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
bool httpsResult = WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
like image 83
CaptainPlanet Avatar answered Oct 08 '22 16:10

CaptainPlanet