Uso de custom exceptions en aplicaciones GTK# con Monodevelop

Hace unos días publiqué una entrada que mostraba el uso de excepciones personalizadas y como ejemplo de esa técnica un proyecto de consola de MonoDevelop que obtenía registros de una tabla en una base de datos PostgreSQL, derivado de ese ejemplo hice una aplicación en GTK# la cual muestra los mismos conceptos pero ahora con un formulario gráfico, por lo que hice algunas modificaciones con respecto al proyecto de consola de manera que pueda entenderse de una mejor manera.
Los pasos son:

  1. Ejecutamos MonoDevelop y creamos un proyecto GTK# llamado GtkPostException
  2. Descargamos y descomprimimos el código del ejemplo de excepciones de este enlace.
  3. Con el botón derecho encima del icono de la solución agregamos las siguientes clases a la solución.
  4. Book.cs
    BooksDataManager.cs
    DataBaseException.cs
    Logger.cs
    RuntimeException.cs
    
  5. Una vez agregadas las clases a la solución verificamos y en su caso editamos para que cada clase se agrupe dentro del namespace GtkPostException.
  6. Creamos un formulario con dos controles label, un control TextView (en donde teclearemos la Connection String), un control Treeviewdonde mostramos el resultado de la consulta y un botón de manera que el formulario tenga el aspecto visual de la siguiente imagen:
  7. Cambiamos el código de la clase BooksDataManager en el método SelectAll para que reciba un parámetro string con el valor de la Connection String recibida desde la interfaz de usuario. Aquí el listado completo de la clase:
  8. Agregamos al evento Clicked del Botón el metodo ExecuteQuery, cuyo código se muestra a continuación:
  9. protected virtual void ExecuteQuery (object sender, System.EventArgs e)
    {
    try{
    AddColumns(GridOutput);
    GridOutput.Model = CreateModel();
    lbmsg.Text += "Consulta ejecutada";

    }catch(GtkPostException.DataBaseException ex){
    MessageBox(ex.Message);

    }
    catch(GtkPostException.RuntimeException ex){
    MessageBox(ex.Message);

    }
    }
  10. El listado completo de la clase MainWindow se muestra a continuación:
  11. using System;
    using Gtk;
    using GtkPostException;

    public partial class MainWindow : Gtk.Window
    {
    public MainWindow () : base(Gtk.WindowType.Toplevel)
    {
    Build ();
    }

    protected void OnDeleteEvent (object sender, DeleteEventArgs a)
    {
    Application.Quit ();
    a.RetVal = true;
    }
    protected virtual void ExecuteQuery (object sender, System.EventArgs e)
    {
    try{
    AddColumns(GridOutput);
    GridOutput.Model = CreateModel();
    lbmsg.Text += "Consulta ejecutada";

    }catch(GtkPostException.DataBaseException ex){
    MessageBox(ex.Message);

    }
    catch(GtkPostException.RuntimeException ex){
    MessageBox(ex.Message);

    }
    }

    void MessageBox(string messageText){
    using(Dialog dialog = new MessageDialog(this,
    DialogFlags.Modal | DialogFlags.DestroyWithParent,
    MessageType.Error,
    ButtonsType.Ok,
    messageText,"")){
    dialog.Run();
    dialog.Hide();
    }
    }
    //Creamos los encabezados de las columnas
    void AddColumns (TreeView treeView) {
    CellRendererText rendererText = new CellRendererText ();
    string[] s = {"Titulo","Año","Páginas","Autores"};
    TreeViewColumn column;
    for(int i = 0;i < s.Length;i++){
    column = new TreeViewColumn (s[i], rendererText, "text", i);
    column.Resizable = true;
    column.MinWidth = 128;
    treeView.AppendColumn (column);
    }
    }
    //Creamos el modelo de datos
    ListStore CreateModel(){
    ListStore store = new ListStore(typeof(string),
    typeof(int),
    typeof(int),
    typeof(string));

    foreach(Book b in BooksDataManager.SelectAll(txtConnStr.Buffer.Text)){
    store.AppendValues(b.Title,b.PubYear,b.NumPages,b.Authors);
    }

    return store;
    }
    }

Si se compila correctamente al ejecutar la aplicación veremos una pantalla como la siguiente imagen:

Al presionar el botón OK mostrará los registros de la tabla conforme a la consulta, como en la siguiente imagen.

Hasta aquí el flujo normal de la aplicación o happy path,ahora vamos a ocasionar una excepción reemplazando el usuario postgres por el usuario sa el cual no existe en la base de datos hecho esto presionamos el botón para que se muestre la excepción personalizada en un cuadro de dialogo, esta excepción queda a nivel base de datos de ahí que lance una DataBaseException.

Este tipo de excepciones son registradas por PostgreSQL si el proceso del servidor se ejecutó desde una terminal como en la siguiente imagen:

Para generar la excepción a nivel aplicación en vez del valor de la Connection String tecleamos cualquier cadena no válida con lo que al presionar el botón nos mostrará el mensaje referente a la clase RuntimeException como en la siguiente imagen:

El detalle a nivel técnico de las excepciones originales se podrá consultar en el archivo log.txt el cual por lo general no es accesible al usuario final sino únicamente al personal técnico.
A continuación el enlace para descargar el ejercicio completo.

  Descarga el código fuente

Uso de Custom Exceptions (excepciones personalizadas) en .NET parte II

En la entrada anterior del blog, me olvide de publicar el archivo App.config donde se encuentra la cadena de conexión (ConnectionString) y se accede a su valor mediante la siguiente línea en la aplicación y se asigna a la variable connStr.



En caso de ser necesario y de tener algún incoveniente en construir la solución aqui dejo el enlace para descargar el código fuente.

  Descarga el código fuente

Uso de Custom Exceptions (excepciones personalizadas) en .NET

Las excepciones (exceptions) son un mecanismo incorporado en .NET que ayuda a la detección de condiciones excepcionales en nuestras aplicaciones, entiéndase por condiciones excepcionales aquellas situaciones que están fuera de nuestro control y que no podemos prever como programadores, esto es distinto de los errores de código y de los errores de aplicación ya que estos si son prevenibles y manejables dentro del ciclo de desarrollo.
Como ejemplos de condiciones excepcionales tenemos:

  • Conectarse a una base de datos que se encuentra offline.
  • Conectarse a una base de datos y tratar de ejecutar un store procedure que no existe.
  • Leer de un archivo en disco que no se encuentra en una determinada ruta.
  • Convertir una cadena de caracteres o alfanumérica hacia un tipo numérico.
  • Ejecutar una acción cuando ya no hay memoria disponible en el sistema operativo.
  • Cuando se hace referencia a un elemento no creado o que se encuentra fuera de los límites de un arreglo.

En .NET la técnica para el manejo de estas condiciones se conoce como structured exception handling (SEH) (la traducción sería más o menos manejo estructurado de excepciones) esta técnica a base de bloques es parte integral de .NET y aplicable a cualquier lenguaje que se ejecute en .NET, en esencia parte de dos clases ApplicationException y SystemException que heredan de la clase System.Exception y que agrupan las excepciones en dos categorías, la primera representa excepciones lanzadas por las aplicaciones y la segunda las del CLR, las clases para excepciones incluidas en .NET son derivadas de estas clases que cubren los casos más comunes y para su empleo se usa la combinación de cuatro palabras reservadas: try,catch throw, finally como se detalla a continuación en los pasos siguientes:

1-. Se pone dentro de un bloque try aquel código que podría tener un evento inesperado.

try
{
         Paso1();
         Paso2();
         Paso3();
}

2-.Al final del bloque try puede ir acompañado o no de varios bloques catch, típicamente aparece la palabra catch con la clase que manejará el error si la palabra catch no especifica una clase entonces atrapara todas las posibles excepciones, cuando se enumeran una a una las posibles condiciones de excepción es MUY IMPORTANTE la jerarquía de clases ya que cada bloque debe ir de la clase más específica a la clase más general, por ejemplo:

       catch(NpgsqlException ex){  //derivada de DbExeption
       }
       catch(DbException ex){  //derivada de ExternalException
       }
       catch(ExternalException ex){ //derivada de SystemException
       }
       catch(SystemException ex){ //derivada de Exception
       }
       catch(Exception ex){ //derivada de Exception
       }

3-. Dentro de cada uno de los bloques catch se coloca el código para el manejo de la excepción como agregar nueva información a la excepción, establecer valores predeterminados de variables o lo más común aquí es tener un Log o bitácora para registrar la excepción, después hay que reenviar o arrojar la excepción a la clase que ejecuto ese código, hay dos alternativas a esto enviar la excepción tal cuál o bien enviar una excepción personalizada que sea de valor para las capas que llamaron la ejecución del código.

        catch(NpgsqlException ex){  //derivada de DbExeption
           EscribeBitacora(ex.Message); 
         }

4-. En el bloque finally se coloca el código que siempre será ejecutado haya ocurrido o no una excepción, por lo general en este bloque se coloca código de limpieza (cleanup) por ejemplo se cierran conexiones de red o a bases de datos, se liberan recursos utilizados o se cierran archivos abiertos entre otros usos.

      finally {
            CloseConnectionDB();
            CloseNetWorkConnection();
            CloseFileOpenToWrite();
         }

Las excepciones no deben ocasionar que la aplicación se colapse por completo por lo que una buena estrategia de desarrollo es manejar las excepciones y responder al evento que las ocasiono. Aunque el uso clases predeterminadas dentro del Framework es adecuado presenta una desventaja por el tipo de mensaje predeterminado ya que para el usuario esa información no debe ser de su conocimiento y en la mayoría de los casos no le encuentra utilidad, por lo que es necesario envolver la excepción dentro una técnica para personalizar excepciones.

La técnica para el uso personalizado de Excepciones

.NET permite crear excepciones personalizadas que envuelven las excepciones originales por excepciones que tengan nuevas características como por ejemplo: mensajes más significativos para el usuario, traducciones o que pueden tener información adicional.
Los pasos para crear una excepción personalizada son:

1-. Crear una nueva clase con el sufijo Exception como una buena práctica y recomendación las clases derivadas de Exception utilizan el este sufijo.

     class RuntimeException
     {
      }

2-. Derivar esta clase de ApplicationException, aunque se podría derivar directamente de Exception, no se considera una buena práctica.

     class RuntimeException : ApplicationException 
     {
      }

3-. La clase debe de tener tres constructores dos adicionales al constructor predeterminado o vacio, como se muestra en el siguiente código:

     public class RuntimeException : ApplicationException
     {
      public RuntimeException(string message): base(message){ }
      public RuntimeException(string message, Exception inner): base(message, inner){}
      }

Como ejemplo de estos conceptos vamos a crear una aplicación que se conecta a una base de datos PostgreSQL, lee y muestra los registros de una tabla llamada Books y donde hace uso de dos excepciones personalizadas: DataBaseException y RuntimeException.
En Monodevelop o en Visual Studio creamos una aplicación de consola, como en las siguientes imágenes.

Creamos una base de datos en PostgreSQL llamada curry y una tabla llamada Books que tendrá los campos como en la siguiente imagen:

Aquí el Script de creación de la tabla

Una vez creada la base de datos y el proyecto, creamos la siguiente clase de entidad.

Las clases derivadas y personalizadas que muestran con los constructores básicos del manejo de excepción.
La clase que maneja las excepciones en base de datos



La clase que maneja las excepciones de la aplicación.



La clase de acceso a datos



La clase logger que se encargara de registrar las excepciones.



Por último la clase principal en donde usamos las excepciones personalizadas.



Una vez creadas estas clases dentro del proyecto la estructura se verá más o menos así en MonoDevelop

Para ejecutar este programa siendo una aplicación de consola debemos de habilitar la salida en una terminal independiente en el menú Project del menú principal elegimos la opción Project properties donde nos aparece la siguiente ventana.

Ahí seleccionamos la opción Run on external console, ahora al ejecutar el programa el resultado se verá en una ventana terminal independiente como en la siguiente imagen que muestra el resultado sin ninguna excepción.

Sin embargo si ocurre una excepción relacionada con la base de datos se mostrará la salida como en la siguiente imagen.

Si hay una excepción en la aplicación se mostrará el resultado como en la siguiente imagen.

La técnica de custom exceptions permite la separación entre el código de flujo de la aplicación y el código de manejo de excepciones lo que hace la aplicación cumpla con un mecanismo mínimo de calidad y sea mucho más manejable, robusta y escalable.

  Descarga el código fuente

Uso de Destructores en C#

En lenguajes orientados a objetos como C#,C++ o Java los objetos tienen un ciclo de vida el cual inicia cuando se crea el objeto mediante un constructor y acaba cuando se termina el objeto mediante un destructor.
Por ejemplo con la palabra reservada new, llamamos al constructor de un
objeto del tipo router:

El uso de constructores es igual en C# como lo es en C++ y Java, donde sino especificamos el constructor, el compilador se encarga de crearlo ya que una de sus responsabilidades es la llamada a un constructor el cual como un estándar tomado de C++ el constructor tiene el mismo nombre que la clase.
De igual forma la clase puede tener el constructor predeterminado sin argumentos, como un constructor personalizado, por ejemplo en el siguiente código:

En C# a diferencia de C++ existe el Garbage Collector (recolector de basura) que se encarga de destruir los objetos que fueron creados y ya no son utilizados, por lo que el programador no es responsable de liberar recursos asignando un destructor a cada objeto.

Sin embargo hay casos en C# donde los destructores son necesarios para objetos que hacen uso de recursos no administrados (unmanaged resources) como las conexiones hacia las bases de datos o el uso de archivos.
Los destructores a diferencia de los constructores no se heredan, no pueden recibir parámetros y no pueden sobrescribirse.
La sintaxis de un destructor es con el mismo nombre que el constructor solo se agrega una ~ como prefijo, como se muestra en el siguiente código:


A continuación el programa principal para ejemplificar los destructores

En este ejemplo el código dentro del destructor imprime un mensaje en la consola lo cual es algo trivial, esto es importante ya que en la mayoría de la documentación que hablan acerca de destructores en C# señalan que deben usarse con extremo cuidado.Hay ciertas reglas acerca de su uso:

  1. Se debe tener presente es nunca utilizar destructores en managed code (código manejado) ya que representa un problema de desempeño para el garbage collector, ya que a diferencia de C++ el objeto no es destruido inmediatamente cuando es ejecutado el destructor.
  2. En lugar de destructores utilizar Close() o Dispose().
  3. NUNCA poner código en el destructor que realice cambios críticos al ambiente o bien código que utilice recursos, es decir los destructores se usaron para liberar no para utilizar.
  4. No se debe hacer referencia a otros objetos dentro del destructor.
  5. Nunca llames a un constructor de forma directa, el garbage collector
    lo invoca de forma automática, si se requiere liberar recursos de forma
    determinística lo recomendable es usar la interfaz IDisposable.

Es posible invocar y controlar el Garbage Collector vía los métodos estáticos de la clase System.GC, pero no es recomendable ya que se activa para todas las aplicaciones que utilicen recursos en ese momento no únicamente para la aplicación que lo invoco, además que debemos de conocer los métodos no determinísticos para la liberación de memoria.
A continuación la salida del programa

Download el código fuente para Xamarin Studio o Visual Studio

Diferencias entre C# DateTime.Now y DateTime.Today

Hoy por la tarde haciendo un programa para enviar mensajes hacia un servidor me salió un error simple que después de cierto tiempo pude resolverlo y se debió más a un bloqueo de mi memoria que ha otro factor.
Resulta que uno de los requisitos en el programa era enviar como título del mensaje fecha, hora, minutos y segundos en los que cada mensaje se había generado.
Básicamente existía una clase mensaje con una propiedad DateCreated como en el siguiente código:


Al crear el mensaje, el programa debía notificar con un aviso, indicando fecha, hora, minutos y segundos, algo así como lo siguiente:

“Mensaje recibido 24-02-2011 a las 22:04:12”

Sin embargo el mensaje lo notificaba de la siguiente forma:

“Mensaje recibido 24-02-2011 a las 22:04:00 ”

El código principal era más o menos asi


Al revisar el código descubrí que al usar la estructura DateTime utilice la propiedad Today en lugar de la propiedadNow .
Ambas propiedades obtienen el valor de la fecha actual, la diferencia es que en Today la parte correspondiente al tiempo se establece en 00:00:00.

al cambiar la propiedad DateCreated como en la siguiente línea:


public DateTime DateCreated
{
get{ return DateTime.Now;}
}

El problema se soluciono y aquí el resultado.

Download el código fuente para Xamarin Studio o Visual Studio

Operadores a nivel de bits en C# (bitwise operators)

Además de los operadores condicionales lógicos y de relación C# cuenta con operadores a nivel de bits (bitwise operators o logical operators) que permiten realizar operaciones con las representaciones binarias de las variables que internamente utiliza la computadora, esto es útil en ciertos casos donde se requiere interactuar directamente con el hardware o utilizar una variable entera como un arreglo de bits donde por ejemplo un tipo short representaría un arreglo de bits con una longitud de 16 valores y cada bit podría ser utilizado como si fuera un valor booleano 1 igual true y 0 igual a false.

Los tipos de datos donde usualmente aplican estos operadores son: los numéricos y las enumeraciones.

La siguiente tabla muestra los tipos numéricos, su longitud en bytes y su valor en decimal.

Así por ejemplo si tenemos valores decimales representados en variables byte (8 bits hasta 255 en decimal)

byte a = 22;
byte b = 33;

Internamente su representación en binario es:

22 = 00010110
33 = 00100001

si utilizamos variables de tipo short (16 bits hasta 65,535)

short c = 666;
short d = 6666;

su representación en binario es:

666 = 00000010 10011010
6666 = 00011010 00001010

Así con cada tipo numérico siempre agrupando las cadenas de bits de 8 en 8.
La siguiente tabla muestra los operadores bitwise, su significado y su resultado.

A continuación un ejemplo de la utilización de estos operadores con enteros, este programa tiene 3 clases:

  1. BitwiseGUI.class: Contiene el código para las interacciones del usuario con el programa, como el menú,la pausa y la impresión del resultado.
  2. BitwiseMath.class: Contiene las operaciones unarias y binarias de los operadores.
  3. MainClass.class: Es el programa principal en donde se evalua la opción ingresada por el usuario.

Compilamos y ejecutamos el programa desde Monodevelop

Al ejecutarlo veremos los siguientes resultados:

Otro uso común de estos operadores esta en las enumeraciones como en el caso de los valores de las enumeraciones FileMode y FileAccess del siguiente código.

    
FileStream outStream = new FileStream("log.txt",FileMode.Append | FileMode.Create,
FileAccess.Read | FileAccess.Write,FileShare.Read);
StreamWriter sw = new StreamWriter(outStream);
sw.WriteLine("Archivo de log");
sw.Close();

  Descarga el proyecto.