I received a question regarding this post on WCF and what my handlers look like when a client disconnects (either because of a fault or the client connection is closed). It's fairly simple. Here's the code used to hook up the events:
IClientCallback remoteMachine = OperationContext.Current.GetCallbackChannel<IClientCallback>();
OperationContext.Current.Channel.Faulted += new EventHandler(ClientFaulted);
OperationContext.Current.Channel.Closed += new EventHandler(ClientClosed);
As a side note, I haven't quite gotten in the habit of using the new/shortened syntax for hooking up delegates. The code above can actually now be written as:
OperationContext.Current.Channel.Faulted += ClientFaulted;
OperationContext.Current.Channel.Closed += ClientClosed;
At any rate, the code in both handlers is actually the same, so I'll just show ClientClosed:
/// <summary>
/// Called whenever a client machine's connection is closed.
/// Automatically removes them from our internal list of clients.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ClientClosed(object sender, EventArgs e)
{
IClientCallback remoteMachine = sender as IClientCallback;
this.RemoveClientMachine(remoteMachine);
}
All it does is cast the sender to the IClientCallback interface and call another method which actually removes it from my internal list. Here's what that code is doing (actually, I send out another notification in the real code to any other clients to let them know something has changed). It just locks the list then uses a lambda to find the client in the list, and if it's found, it's removed.
private void RemoveClientMachine(IClientCallback remoteMachine)
if (remoteMachine != null)
RegisteredClient client;
// Unregister them automatically
lock (m_callbackList)
client = m_callbackList.Find(c => c.CallBack == remoteMachine);
if (client != null)
m_callbackList.Remove(client);
One interesting failure scenario I found occurred when you had a large number of clients connected and something like your main network line goes down. In some cases I wouldn't receive a notification for every client to remove them from a list (I'm guessing it was firing so many events some of them were being lost). At any rate, the easiest way for me to address this was to include a watchdog timer which would periodically sweep through the connections and attempt to determine if they were still valid. Here's what that looks like:
public void CheckCallbackChannels()
RegisteredClient[] clientList = new RegisteredClient[0];
clientList = new RegisteredClient[m_callbackList.Count];
m_callbackList.CopyTo(clientList);
foreach (RegisteredClient registeredClient in clientList)
ICommunicationObject callbackChannel = registeredClient.CallBack as ICommunicationObject;
if (callbackChannel.State == CommunicationState.Closed || callbackChannel.State == CommunicationState.Faulted)
this.RemoveClientMachine(registeredClient.CallBack);
Links:
http://www.rcs-solutions.com/blog/2008/07/06/WCFNotificationOnDisconnect.aspx
Remember Me
a@href@title, b, i, strike