Monday, March 2, 2009

Handle Network Availability Changes.

I have recently been working on an application that has multiple instances of a WPF application that interfaces with a database. Each of the applications relies on SQLDependency notifications to stay in sync when a change is made by one. The database notifies all applications that are subscribed to notifications when one of the applications makes an update.

This is all well and good, until the test team got ahold of the application. They always have a knack for thinking of things that I have not handled, guess that is their job. This particular event was a very simple and distinctly possible occurrence, they unplugged the network cable. Doing this threw the message notification into all sorts of disarray, and the application would only recover after it was shut down and restarted. Bad programming on my part. Back to the drawing board.

Turns out the .NET framework has a method for handling just this sort of event. The NetworkChange class contains two events that can easily be subscribed to and handled; NetworkAvailabilityChange and NetworkAddressChange.

So, we start by creating an eventhandler when we load out application. It looks something like this.

NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler (NetworkChange_NetworkAvailabilityChanged);

After subscribing to the event we of course have to define what happens when the event fires. My method looks like the following.

void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
        {
            if (e.IsAvailable)
            {
                try
                {
                    // This event will occur on a thread pool thread.
                    // Updating the UI from a worker thread is not permitted.
                    // The following code checks to see if it is safe to
                    // update the UI.
                    DispatcherObject i = (DispatcherObject)this;

                    // If CheckAccess returns True, the code
                    // is executing on a worker thread.
                    if (!this.Dispatcher.CheckAccess())
                    {
                        // Create a delegate to perform the thread switch.
                        NetworkAvailabilityChangedEventHandler tempDelegate =
                            new NetworkAvailabilityChangedEventHandler NetworkChange_NetworkAvailabilityChanged);

                        object[] args = { sender, e };

                        // Marshal the data from the worker thread
                        // to the UI thread.
                        i.Dispatcher.BeginInvoke(tempDelegate, args);

                        return;
                    }

                    //Drop and restart the SqlDependency Cache to recover from the network outage.  The
                    //subscription will be rebuilt after the data is refreshed in the GetData() method.
                    netDown = false;
                    SqlDependency.Stop(Utils.GetConnectionString("ConnectionString"));
                    SqlDependency.Start(Utils.GetConnectionString("ConnectionString"));

                    // Reload the data for the list view.
                    GetData();
                }
                catch (Exception ex)
                {
                    System.Diagnostics.EventLog.WriteEntry("Terminal", ex.Message);
                }
            }
            else
            {
                netDown = true;
            }
        }

The NetworkChange_NetworkAvailibiltyChanged event will occur on a worker thread. Updating the UI from a worker thread is not permitted. The code in this method checks to see if you have permission to update the ui and if not will create a delegate to perform the thread switch and update the UI. In this case my GetData() method updates the user interface so we have to call the NetworkAvailibilityChangedEventHandler via a delegate.