WCF Duplex: How to handle thrown exception in dupl

2019-07-19 02:31发布

How do I handle an exception thrown in a callback method on the client in a WCF duplex setup?

Currently, the client does not appear to raise the faulted event (unless I'm monitoring it incorrectly?) but any subsequent to call Ping() using the the client fails with CommunicationException: "The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it has been Aborted.".

How do I deal with this and recreate the client etc? My first question is how to find out when it happens. Secondly, how best to deal with it?

My service and callback contracts:

[ServiceContract(CallbackContract = typeof(ICallback), SessionMode = SessionMode.Required)]
public interface IService
{
    [OperationContract]
    bool Ping();
}

public interface ICallback
{
    [OperationContract(IsOneWay = true)]
    void Pong();
}

My server implementation:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
public class Service : IService
{
    public bool Ping()
    {
        var remoteMachine = OperationContext.Current.GetCallbackChannel<ICallback>();

        remoteMachine.Pong();
    }
}

My client implementation:

[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Single)]
public class Client : ICallback
{
    public Client ()
    {
        var context = new InstanceContext(this);
        var proxy = new WcfDuplexProxy<IApplicationService>(context);

        (proxy as ICommunicationObject).Faulted += new EventHandler(proxy_Faulted);

        //First Ping will call the Pong callback. The exception is thrown
        proxy.ServiceChannel.Ping();
        //Second Ping call fails as the client is in Aborted state
        try
        {
            proxy.ServiceChannel.Ping();
        }
        catch (Exception)
        {
            //CommunicationException here 
            throw;
        }
    }
    void Pong()
    {
        throw new Exception();
    }

    //These event handlers never get called
    void proxy_Faulted(object sender, EventArgs e)
    {
        Console.WriteLine("client faulted proxy_Faulted");
    }
}

1条回答
我只想做你的唯一
2楼-- · 2019-07-19 02:53

As it turns out, you cannot expect the Faulted event to be raised. So, the best way to re-establish the connection is to do it when the subsequent call to Ping() fails:

I'll keep the code simple here:

public class Client : ICallback
{
    public Client ()
    {
        var context = new InstanceContext(this);
        var proxy = new WcfDuplexProxy<IApplicationService>(context);

        (proxy.ServiceChannel as ICommunicationObject).Faulted +=new EventHandler(ServiceChannel_Faulted);

        //First Ping will call the Pong callback. The exception is thrown
        proxy.ServiceChannel.Ping();
        //Second Ping call fails as the client is in Aborted state
        try
        {
            proxy.ServiceChannel.Ping();
        }
        catch (Exception)
        {
            //Re-establish the connection and try again
            proxy.Abort();
            proxy = new WcfDuplexProxy<IApplicationService>(context);
            proxy.ServiceChannel.Ping();
        }
    }
    /*
    [...The rest of the code is the same...]
    //*/
}

Obviously, in my example code, the Exception will be thrown again but I hope this is useful to give people an idea of how to re-establish the connection.

查看更多
登录 后发表回答