Silverlight 3 Beta 1:  Conciencia de Conexión

Nota: Este artículo ha sido reemplazado por este otro:

https://rdiazconcha.com/2010/06/silverlight-4-conciencia-de-conexin/

El nuevo espacio de nombres System.Net.NetworkInformation de Silverlight, incorporado en Silverlight 3 Beta 1 nos permite implementar una funcionalidad de “conciencia” de conexión en nuestras aplicaciones, esto es, saber en un momento dado si la aplicación está ejecutándose en un ambiente conectado o ha perdido la conexión; para poder determinar un comportamiento correcto en cada uno de esos escenarios.  Esta funcionalidad nos sirve tanto para aplicaciones que se estén ejecutando dentro del Navegador como en aplicaciones Fuera del Navegador, es por eso que dejé este tema como un artículo por separado (ver el artículo Silverlight 3 Beta 1:  Fuera del Navegador para más información al respecto de este tipo de aplicativos).

Clase NetworkInterface

Esta clase abstracta incluye el método estático GetIsNetworkAvailable(), el cual nos indica si hay una conexión de red o no.

Es muy importate mencionar que este método NO indica si hay una conexión a Internet, es decir, no está directamente relacionado una conexión de red disponible a una conexión en Internet efectivamente.  Una manera para conocer si tenemos una conexión a Internet es hacer ping a un sitio conocido y con alta disponibilidad (ejemplo: www.microsoft.com, o www.yahoo.com) y/o utilizar las clase WebClient para descargar un archivo conocido en nuestro servidor donde esté hospedada la aplicación, por ejemplo: un archivo de texto pequeño que podamos descargar y leer para determinar si efectivamente tuvimos acceso a través de Internet.

El siguiente fragmento de código muestra cómo podemos utilizar NetworkInterface.GetIsNetworkAvailable() para determinar si tenemos una conexión de red:

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        btn.Click += (s, a) =>
        {
            txt.Text = NetworkInterface.GetIsNetworkAvailable().ToString();
        };
    }
}

Clase NetworkChange

Un paso más adelante en esta funcionalidad está la clase NetworkChange la cual incluye el evento NetworkAddressChanged.  Este evento es disparado cuando hay un cambio en el estado de la conexión de red y está basado en el delegado NetworkAddressChangedEventHandler.  Si lo usamos junto con NetworkInterface.GetIsNetworkAvailable() podemos tener un mecanismo para automáticamente saber si nuestra aplicación está ejecutándose en un ambiente con o sin conexión.

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        NetworkChange.NetworkAddressChanged += (s, a) =>
        {
            if (NetworkInterface.GetIsNetworkAvailable())
            {
                //Se ha restablecido la conexión de red
            }
            else
            {
                //No ha conexión de red
            }
        };

    }
}

Nota: Este evento no se disparará si simplemente pones tu Navegador ‘Work Offline’

Construyendo la Clase NetworkChangeExtended

Gracias a que la clase NetworkChange no está marcada como sellada, podemos crear fácilmente una clase que extienda esta funcionalidad para determinar no solo si hay conectividad de red, sino determinar que exista realmente conexión a Internet.

A continuación les presento el código de una clase llamada NetworkChangeExtended, la cual efectivamente hereda de NetworkChange pero que incluye la funcionalidad para detectar si hay conexión de Internet o no, por medio del uso de un objeto de tipo WebClient para descargar un archivo de texto llamado Archivo.txt.  Archivo.txt deberá estar en el sitio de origen (/ClientBin de manera predeterminada) y deberá contener algo de texto.

using System;
using System.Net;
using System.Net.NetworkInformation;

namespace SL3ConcienciaConexion
{
    /// <summary>
    /// Event Arguments
    /// </summary>
    public class InternetAvailableEventArgs : EventArgs
    {
        /// <summary>
        /// Español: Indica si hay conexión a Internet disponible
        /// English: Indicates if there is Internet connection available
        /// </summary>
        public bool Available { get; set; }
    }

    public class NetworkInterfaceExtended : NetworkInterface
    {

        public static event EventHandler<InternetAvailableEventArgs> InternetAvailable;

        /// <summary>
        /// Español: Indica si hay conexión a Internet por medio de la descarga de un archivo a través de un objeto WebClient
        /// English: Indicates if there's Internet connection available through the download of a file using a WebClient object
        /// </summary>
        public static void GetIsInternetAvailable()
        {
            bool result = false;
            if (GetIsNetworkAvailable())
            {
                WebClient client = new WebClient();
                client.DownloadStringCompleted += (s, a) =>
                {
                    if (a.Error == null)
                    {
                        if (!string.IsNullOrEmpty(a.Result))
                        {
                            result = true;
                        }
                    }
                    else
                    {
                        result = false;
                    }

                    OnInternetAvailable(result);
                };
                client.DownloadStringAsync(new Uri("Archivo.txt", UriKind.RelativeOrAbsolute));
            }
            else
            {
                OnInternetAvailable(result);
            }

        }


        /// <summary>
        /// Español: Dispara el evento InternetAvailable
        /// English: Fires the InternetAvailable event
        /// </summary>
        /// <param name="available"></param>
        private static void OnInternetAvailable(bool available)
        {
            if (InternetAvailable != null)
            {
                InternetAvailable(null, new InternetAvailableEventArgs() { Available = available });
            }
        }
    }
}

Para usarla simplemente nos inscribimos al evento InternetAvailable, el cual se disparará cuando haya un cambio en el estado de la conexión a Internet:

using System.Windows.Controls;
using System.Net.NetworkInformation;

namespace SL3ConcienciaConexion
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            NetworkInterfaceExtended.InternetAvailable += (s, a) =>
            {
                txt.Text = a.Available.ToString();
            };

            Loaded += (s, a) =>
            {
                NetworkInterfaceExtended.GetIsInternetAvailable();
            };

            NetworkChange.NetworkAddressChanged += (s, a) =>
            {
                NetworkInterfaceExtended.GetIsInternetAvailable();
            };

        }
    }
}

El siguiente screencast muestra el uso de esta clase en una aplicación de Silverlight 3 beta 1.  El screencast muestra cómo inicialmente se cuenta con acceso a Internet, posteriormente se desconecta el cable de red logrando así que la clase detecte el cambio y despliegue en el TextBlock si hay conexión a Internet o no.  Finalmente se vuelve a conectar el cable para tener el estado inicial.

Resumen

La funcionalidad de Conciencia de Conexión presente en Silverlight 3 Beta 1 es un instrumento bastante útil para que nuestras aplicaciones puedan determinar si están ejecutando en un ambiente con conectividad de red o no.  Asimismo, vimos cómo es fácil extender dicha funcionalidad para incluir un mecanismo de detección de acceso a Internet, a través de una clase que extienda la clase NetworkInterface y que haga uso de un objeto WebClient para descargar asíncronamete un archivo del servidor, por lo tanto determinar la presencia de una conexión a Internet.