天道酬勤

博观而约取,厚积而薄发!
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Handling Disconnects with WCF

Posted on 2010-04-30 12:22  Happy Coding  阅读(379)  评论(0编辑  收藏  举报

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