How to detect on a WCF Service that a client just got disconnected?
One of this days, I had to work on a problem where we needed to detect an unexpected disconnection of a WCF Client. This seems pretty straightforward, right?
So lets add a couple of more information to this scenario here. Basically, they had a very simple WCF Client Console Application that was consuming a Self-Hosted WCF Service.
This client could be disconnected by a great variety of reasons:
- Internal Fault
- Application Crash
- Network Issues
In this case they needed to use NetTcpBinding to the communication between the Client and the Server.
The reason behind this exercise was to guarantee that every time the client gets disconnected they could detect that on the Server side and provide some clean up code and resources release (I know, I know, there are better ways to achieve that, but lets just play along with this).
At first this seems not hard to implement, in fact every time they had a graceful shutdown on the client side the Server gets the close notification and all is well, however if for some reason the client crashes or loose connection, the Server never receives the Close notification.
So, based on all this, I had to enumerate what we can do and what we cannot do on this scenario so they can make the correct decision on their scenario, so here it goes:
They could register 'Closed' or 'Faulted' event handler of the channel.
OperationContext.Current.Channel.Closed += ChannelClosed]
However we need to remember that for network disconnects server does not get any notification. The only other option here would be work with the receiveTimeout in binding itself.
Another important point though is the fact the Close could take some time to fire could be due to client getting disconnected and service not getting any notification. In this case, Close event will be called after:
- If service is processing some request by client and while service is processing request, client disconnects, Server will get information about client getting disconnected when it tries to reply.
- Otherwise, Close event should be fired after receiveTimeout occurs.
Another, quick way to identify if client has disconnected would be enabling reliableSession on channel and keep inactivityTimeout low. In this case, if client is disconnected, Close event will be fired on exceeding inactivityTimeout. In this case if see client channel getting closed due to poor network which can be established again, we could use reliable session with default or higher timeout.
Relevant note here would that to recognize that reliable sessions must buffer sent messages on the client for redelivery if a message gets lost in transfer and must hold messages on the service before handing them to the service implementation to preserve message order in case messages are received out-of-sequence, so that would had some extra complexity to our scenario.
And that's it, based on this we could make our decisions with all the relevant information on our hands to support the our decision.
Hope that helps