开发者

Wcf Duplex: Retrieve Client Connection?

Hi

Maybe this look like ridiculous but this is problem at least for me

I wrote duplex WCF service, in my service I need to get active client service and save them, and when with occurred special event I call specific client and send some values for it. So I define dictionary and save client in that. (With this method client calls)

 public static Dictionary<int, IServiceCallbak> ActiveClients;
    public void IConnect(int SenderId)
    {
            if (ActiveClients == null)
                ActiveClients = new Dictionary<开发者_高级运维int, IServiceCallbak>();
            Client = OperationContext.Current.GetCallbackChannel<IServiceCallbak>();
            if (ActiveClients.Count(ac => ac.Key == SenderId) > 0)
                ActiveClients.Remove(SenderId);
            ActiveClients.Add(SenderId, Client);
    }

So then when I need find client from that dictionary and call specific method : Client.DoSomthing().

Also when Client wants to exit, it calls IDisconnect method which will remove client from dictionary.

so I manage Active-client in service!!!

But there is problem in client for managing themselves After a period time which define in app.config service connection will be closed and you should renew that and then open the service.

So in this case:

1)Is there any solution for recreate and open the service object automatically in client.

2)Or when in server side when service want call clients, check state of client-service-object from that dictionary, and reopen connection from server-side (Ridiculous-solution)

Edit

I think better solution is to handle Suggestion 1, I don't know how!!!.

So for now the question is: Is way exist to do Suggestion 1 Or not? Previously I describe Suggestion 1 in Comment:

"And automatically refer to event for this case(like closing or aborting), but I don't find anything for doing this in Service-Client"


In order to prevent the server side from closing the connection you could set up a Heartbeat() method in the contract that the client could call periodically. This is not ideal however, for one thing because the underlying socket could drop and this does nothing to remedy that.

As far as your suggestion 1) if on the client side you are inheriting from ClientBase you are somewhat stuck in that no indication of a problem may be given until you call a method to route to the service. You would have to wrap the call in a try / catch and then employ some reconnect logic:

public class MyClass : ClientBase<IContract>, IContract
{
    public void ServiceMethod(String data) {
        try {
            base.Channel.ServiceMethod(data);
        }
        catch (CommunicationException ce) {
            // Perform some reconnect logic here
            base.Channel.ServiceMethod(data);
        }
    }
}

Your comment for suggestion 2) is correct, if there are any firewalls between the server side and client they would most likely not allow the connection

Edit: To expand on my suggestion for 1), you would need to create a new connection when the call to the service fails with a CommunicationException. The simplest approach would be to create the service channel in the constructor and then create another when the call fails:

class ServiceClient {
    Service1Client mService;  // Class generated by VS tool
    public ServiceClient()
        : base() {
            mService = new Service1Client();
    }
    #region IService1 Members
    public string GetData(int value) {
        CommunicationState state = mService.State;
        if (state == CommunicationState.Closed || state == CommunicationState.Faulted) {
            mService = new Service1Client();
        }
        try {
            // Note: The state checked above may not be accurate,
            //  hence the try...catch
            return mService.GetData(value);
        }
        catch (CommunicationException) {
            mService = new Service1Client();  // Reconnect logic
            return mService.GetData(value); // If it fails again we are out of luck...
        }
    }
    #endregion
}

Edit2:

In WCF the session is handled by the client, if the session between the client and the service is lost, I know of no way to restore that session, either from the client or the service. You are, unfortunately, stuck here.

If the service wants to send via the callback with a broken session, simply put, it can't. Because of the way networks work the service may not know the actual client address. This and various other issues (like firewalls) mean that trying to reestablish a connection to the client from the service just isn't practical. The only approach for the service is to store what data it wanted to send to the client and send it when the service detects that the client has reconnected.

There is no guarantee that the client will know of the underlying socket dropping, until the client tries to send something over the socket, hence the try...catch. Recreating the channel from the client once it becomes aware of a broken connection is the only way I know of to handle the issue; which is what the code example does.

The heartbeat idea is a way to proactively deal with broken connection. Its efficiency depends on your requirements as to how fast you need to detect a broken connection and how many clients are present. The more clients connected the longer the heartbeat would have to be so that you don't put a load on the network at the service.

Edit3:

After some additional digging there may be a way to do what you want automatically. You can create what is known as a Reliable Session. Activating this involves creating additional entries in the config:

<netTcpBinding>
    <binding>
        <reliableSession ordered="Boolean"
                    inactivityTimeout="TimeSpan"
                    enabled="Boolean" />
    </binding>
</netTcpBinding>

It is also available for Http related bindings, check out the link to the Microsoft documentation on the feature.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜