I received a question regarding this poston WCF and what my handlers look like when a client disconnects (eitherbecause of a fault or the client connection is closed). It's fairlysimple. 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);
Asa side note, I haven't quite gotten in the habit of using thenew/shortened syntax for hooking up delegates. The code above canactually now be written as:
IClientCallback remoteMachine = OperationContext.Current.GetCallbackChannel<IClientCallback>();
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);
}
Allit does is cast the sender to the IClientCallback interface and callanother method which actually removes it from my internal list. Here'swhat that code is doing (actually, I send out another notification inthe real code to any other clients to let them know something haschanged). It just locks the list then uses a lambda to find the clientin 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);
}
Oneinteresting failure scenario I found occurred when you had a largenumber of clients connected and something like your main network linegoes down. In some cases I wouldn't receive a notification for everyclient to remove them from a list (I'm guessing it was firing so manyevents some of them were being lost). At any rate, the easiest way forme to address this was to include a watchdog timer which wouldperiodically sweep through the connections and attempt to determine ifthey were still valid. Here's what that looks like:
public void CheckCallbackChannels()
{
RegisteredClient[] clientList = new RegisteredClient[0];
lock (m_callbackList)
{
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