sábado, 31 de diciembre de 2011

Subnetting en redes IP v4 Parte I

Una dirección IPv4 (IPv4 address) tiene una longitud de 32 bits que se considera única para cada host, esta dirección se escribe en formato binario de izquierda a derecha donde se considera que el bit más significativo es el bit más hacia la izquierda, una IPv4 tiene dos partes, la parte de red (netid) y la parte de host (hostid), originalmente el espacio de direcciones IP fue dividido en tres clases diferentes clase A, clase B y clase C, cada clase se distingue por los primeros bits iniciales o bits de prefijo, como en la siguiente tabla:



La clase A tiene bit de prefijo en 0 y es seguido por 7 bits para la parte de red y 24 bits restantes para la parte de host, la clase B tiene dos bits de prefijo el primero en 1 y el segundo en 0 seguido de 14 bits para la parte de red y de 16 bits para la parte de host, la clase C tiene tres bits de prefijo el primero y el segundo en 1 y el tercero en 0 por lo que tiene 21 bits para la parte de red y 8 bits para la parte de host, existen también las clases D y E las cuales se usa para multicasting y para experimentación respectivamente.

En un principio este esquema pareció ser suficiente para el tamaño de las redes, pero conforme la Internet fue creciendo en número de redes y hosts, este esquema presento deficiencias, una de ellas fue el desperdicio y el agotamiento de direcciones, por lo que una de las soluciones a este problema fue el concepto de subneteo (subnetting) el cual nos permite tomar una dirección de red y crear subconjuntos de esa red o bien subredes esto se logra mediante los siguientes pasos:


Por ejemplo si se nos pide subneteo en una red clase B y se nos da un mascara de 27 bits, la clase B tiene 16 bits para el campo de red y 16 bits para el campo de host.
Se resta el número de mascara menos el número de bits del campo de red y el resultado es el número de bits que debemos de tomar de los octetos del campo de host.
En este caso:



Se utilizan los 11 bits para el subneteo y los 5 bits restantes se utilizan para el campo de host. Por lo que quedaría de la siguiente forma:


Bien ahora que ya tenemos identificados los bits de subred, vamos a poner en práctica como lo obtenemos las subredes en forma decimal.

Supongamos que tenemos una red 130.3.0.0 con una subnet mask de 25 o 130.3.0.0/25


Si necesitamos encontrar los números de subredes: 25 y 400 respectivamente por lo que en principio calculamos el número de bits que necesitaremos para la subred por lo que hacemos la resta:

25-16 = 9 bits para subneteo

Esquematizamos los octetos de la red 130.3.0.0/25, para una mejor comprensión:


En la parte inferior entre el tercero y el cuarto octeto vemos en color verde el número de subredes correspondientes a cada bit de la parte de subred, para la representación del valor en decimal utilizamos los valores de la parte superior, por lo que la suma de cada bit encedido en la parte inferior nos proporcione como resultado el número de subred y la suma de sus valores en la parte superior nos proporcione la representación decimal , así por ejemplo la subred número 25 será:


Hay que distinguir que para el número de subred sumamos los valores que nos den como resultado el número de subred que buscamos, sin importar que se encuentren en diferentes octetos y que para la parte decimal su representación es únicamente la suma de los valores de los bits que componen ese octeto.

Encendemos los valores de subred del tercer octeto en 16 y 8 y el valor de 1 del cuarto octeto para que la suma de sus valores de subred tengamos el número de 25.

16 + 8 + 1 = 25
Ahora entonces sumamos la parte superior del tercer octeto para obtener su representación decimal en este caso:

8 + 4 = 12
Y para el último octeto la representación decimal del bit encendido nos da 128, por lo que juntando todos los octetos obtenemos que la subred 25 se represente por la dirección Ipv4:

130.3.12.128 / 25
Ahora buscamos la representación decimal de la subred 400 utilizando el mismo método



En este caso como es un número par de subred, inferimos que el último octeto no tendrá valor por lo que nos concentramos en los bits del tercer octeto, prendemos el bit de subred 256, el bit 128 y por último el bit 16 de la suma obtenemos los bits de la subred 400.

256 + 128 + 16 = 400
Ahora obtenemos la representación decimal de los bits prendidos en el tercer octeto.

128 + 64 + 8 = 200
La subred 400 queda representada en formato decimal como:

130.3.200.0/25

martes, 27 de diciembre de 2011

Entendiendo Satellite Assemblies usando MonoDevelop - (parte 2)

En la primera parte de este tutorial, se mostró como crear Satellite Assemblies, ahora en este segunda parte se mostrará un listado donde se muestra el código que nos mostrará los pasos de como consumir los ensamblados satélite o ensamblados de recursos desde una aplicación GTK#.


using System;
using Gtk;
using System.IO;
using System.Resources;
using Gdk;
using System.Reflection;

namespace TestResource
{
class MainClass : Gtk.Window
{
DrawingArea darea = null;
Label label1 = null;
Button btnLoad = null;
Pixmap pixmap;
Pixbuf pngbuf;
public MainClass():base("Test Resources"){
BorderWidth = 8;
this.DeleteEvent += new DeleteEventHandler(OnWindowDelete);
Frame frame = new Frame("Load");
Add(frame);
VBox MainPanel = new VBox (false, 8);
label1 = new Label("Query is: ");
darea = new DrawingArea();
btnLoad = new Button("Load resources");
btnLoad.Clicked += AddResource_Clicked;
darea.SetSizeRequest (200, 200);
darea.ExposeEvent += Expose_Event;
darea.ConfigureEvent += Configure_Event;
MainPanel.Add(label1);
MainPanel.PackStart(darea);
MainPanel.Add(btnLoad);
frame.Add (MainPanel);
SetDefaultSize (320, 233);
Resizable = false;
ShowAll();
}
public void OnWindowDelete(object o, DeleteEventArgs args) {
Application.Quit(); }

public static void Main (string[] args)
{
Application.Init();
new MainClass();
Application.Run();
}

void PlacePixbuf (Gdk.Pixbuf buf)
{
pixmap.DrawPixbuf (darea.Style.BlackGC,buf, 0, 0, 0, 0,buf.Width,
buf.Height,RgbDither.None, 0, 0);
darea.QueueDrawArea (0, 0, buf.Width, buf.Height);
}

void LoadResources(){
try{
//find the assembly
string assem = "demo.resources.dll";
Assembly assembly = Assembly.LoadFrom(assem);
if(File.Exists(assem))
{
//Instance for resourcemanager
ResourceManager rm = new ResourceManager("demo",assembly);
//get the string for the resource
label1.Text += rm.GetString("query1");
//get the image for the resource
System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)rm.GetObject("pugme");
bitmap.Save("pugme.png",System.Drawing.Imaging.ImageFormat.Png);
pngbuf = new Pixbuf("pugme.png");
}
}catch(Exception e){
Console.WriteLine(e.Message);
}
}

void Configure_Event (object obj, ConfigureEventArgs args)
{
Gdk.EventConfigure ev = args.Event;
Gdk.Window window = ev.Window;
Gdk.Rectangle allocation = darea.Allocation;
pixmap = new Gdk.Pixmap (window, allocation.Width,allocation.Height, -1);
pixmap.DrawRectangle (darea.Style.WhiteGC, true, 0, 0,allocation.Width,
allocation.Height);
}

void Expose_Event (object obj, ExposeEventArgs args)
{
Gdk.Rectangle area = args.Event.Area;
args.Event.Window.DrawDrawable (darea.Style.WhiteGC,
pixmap,area.X, area.Y,area.X, area.Y,area.Width, area.Height);
}

void AddResource_Clicked (object obj, EventArgs args)
{
LoadResources();
PlacePixbuf (pngbuf);
}
}
}

Toda esta funcionalidad se encuentra en el método LoadResources() , este método comienza primeramente con la carga en tiempo de ejecución del ensamblado que contiene los recursos utilizando las líneas siguientes:

string assem = "demo.resources.dll";
Assembly assembly = Assembly.LoadFrom(assem);

A continuación creamos una instancia de la clase ResourceManager en la cual se encuentran los métodos para obtener los recursos del ensamblado, en este ejemplo obtenemos un recurso de tipo cadena y otro de tipo imagen, con el código de las líneas siguientes

label1.Text += rm.GetString("query1"); 
System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)rm.GetObject("pugme");

Por último únicamente se guarda la imagen en el directorio de la aplicación para crear un objeto Pixbuf el cual se dibujará en un control DrawingArea, esto ocurre en las siguientes líneas:

bitmap.Save("pugme.png",System.Drawing.Imaging.ImageFormat.Png);
pngbuf = new Pixbuf("pugme.png");

Los métodos presentados por este programa en GTK# aplican para cualquier otra aplicación .NET incluso si el lenguaje de programación utilizado no es C#.
>Compilamos la aplicación y ejecutamos la aplicación con los siguientes comandos desde una terminal:

$ mcs –pkg:gtk-sharp-2.0 –r:System.Drawing Main.cs
$ mono Main.exe


Al ejecutar la aplicación se mostrará como en la siguiente imagen:


Al presionar el botón Load resources deberán de cargarse los recursos de cadena e imagen respectivamente, antes de ejecutar la aplicación es importante verificar que el ensamblado demo.resources.dll se encuentre en el mismo directorio de la aplicación.

El resultado final se mostrará como en la siguiente imagen:

Parte del código de este programa se derivo del ejemplo 4-8 del capítulo 4 del libro Mono: A Developer's Notebook de Niel M. Bornstein y Edd Dumbill


domingo, 25 de diciembre de 2011

Entendiendo Satellite Assemblies usando MonoDevelop - (parte 1)

Una de las características más atractivas que .NET ofrece para el desarrollo de software es la capacidad de crear componentes en diferentes lenguajes de programación, esto es posible por que el objetivo de cada compilador existente para .NET es producir un assembly (ensamblado) el cual por definición es: La unidad funcional de distribución, versionamiento y de identidad de la plataforma .NET.
Además de clasificar los assemblies en Strong-Named o privados dependiendo de su instalación o en Single-File y Multi-File si contienen un archivo o varios, pueden también clasificarse en base a su contenido en donde tenemos a los ensamblados que contienen código MSIL y recursos (imágenes, traducciones o archivos de texto, etc) y a los Satellite assemblies (ensamblados satélite) que únicamente contienen recursos.
Para estos últimos ensamblados existen herramientas como Visual Studio o SharpDevelop que nos permiten hacerlo de forma automática, aunque también existe la opción de hacerlo de forma programática con las clases contenidas en el namespace System.Resources.

  • ResourceManager: Permite tener acceso a los archivos de recursos de forma programática.
  • ResourceReader: Lee los archivos binarios de recursos.
  • ResourceWriter: Escribe los archivos binarios de recursos.
  • ResXResourceReader: Lee los archivos XML de recursos.
  • ResXResourceWriter: Escribe los archivos XML de recursos.

En el siguiente programa mostramos el uso de la clase ResourceWriter para crear un satellite asembly. Abrimos MonoDevelop y creamos una solución GTK#, utilizando el diseñador de la interfaz gráfica, creamos una GUI similar a como se muestra en la siguiente imagen:


Construimos un manejador de evento para cada uno de los botones de manera que el código de la clase se vea como en el siguiente listado.

Al compilar y ejecutar el programa podemos ingresar uno a uno el nombre y el valor de la cadena o del archivo de imagen que contendrá nuestro archivo de recursos, en caso de las imágenes debemos habilitar el checkbox “Is image” además de que el archivo de imagen debe encontrarse físicamente en el mismo directorio que el programa, en las siguientes imágenes introduciremos un par de valores de prueba.




Después de ingresar el par de valores podemos generar físicamente el archivo de recursos con el botón “Build Resource”, como en la siguiente imagen:


La funcionalidad del botón “Build Resource” es crear una instancia de la clase ResourceWriter.

rw = new ResourceWriter("demo.resources")
Para después iterar en los valores de cada Hashtable,primero en el Hashtable de las cadenas en la cual utilizara el siguientel metodo:



rw.AddResource(entry.Key.ToString(),entry.Value.ToString());

A continuación itera en el Hastable de las imágenes en donde utiliza el método anterior salvo con la diferencia de convertir el valor en un objeto Bitmap.

rw.AddResource(entry.Key.ToString(),new Bitmap(entry.Value.ToString()));

Por último se utiliza el siguiente método:
rw.Generate();
Para crear físicamente el archivo “demo.resources” el cuál se creará en el mismo directorio donde se ejecuta el programa, como en la siguiente imagen:

Ahora solo falta crear el Satellite Assembly, esto puede lograrse con el compilador de .NET o bien con el Assembly Linker, para este tutorial utilizaremos el Assembly Linker, la instrucción para crear el ensamblado es la siguiente:

$ al /embed:demo.resources /out:demo.resources.dll

Utilizamos la opción /embed para incrustar el recurso en el ensamblado y la opción /out para nombrar al ensamblado resultado, este comando lo ejecutamos desde una terminal de consola como en la siguiente imagen:

Podemos observar que ahora el archivo mono.resources.dll es un ensamblado .NET válido mediante la herramienta MonoDis mediante el comando:

$ monodis mono.resources.dll

Veremos el contenido del ensamblado, como se muestra en la siguiente imagen:


Ahora ya tenemos listo el Satellite Assembly para que sea consumido por cualquier otra aplicación en .NET en la segunda parte mostraremos una aplicación para acceder al contenido del ensamblado.


jueves, 17 de noviembre de 2011

Regular Expressions con C#

Las expresiones regulares (regular expressions) han sido utilizadas con éxito desde hace tiempo como una solución avanzada mucho más compleja y eficiente para el procesamiento y la validación de texto en herramientas como grep, sed, AWK, bash y en lenguajes de programación del tipo scripting como Perl, Python y PHP.


Una expresión regular (regular expression o regexp) es un patrón de cadenas de caracteres formado por una combinación de caracteres especiales llamados metacaracteres o cuantificadores y de caracteres alfanuméricos llamados literales, este patrón representa un lenguaje regular o un conjunto regular de cadenas para tres operaciones básicas: adyacencia, repetición y alteración.


En el sitio http://www.regular-expressions.info/ se da una mayor referencia acerca de los cuantificadores y su significado.


Existen dos implementaciones de expresiones regulares POSIX y PERL, en el caso de .NET el motor de expresiones regulares utiliza la implementación compatible con Perl 5.
Las expresiones regulares en .NET se encuentran integradas como clases dentro del ensamblado System.Text.RegularExpressions estas clases utilizan un motor implementado como un autómata finito no determinístico (NFA) similar al que emplean Perl, Python y Emacs con algunas características propias de .NET.


Para ejemplificar el uso de expresiones regulares en C#, mostraremos un programa sencillo que tenga una funcionalidad similar al comando grep o egrep, como sabemos este comando en su funcionamiento básico recibe como argumentos una expresión regular y uno o varios archivos en donde buscar e imprime las líneas que coincidan con esa expresión regular.


Fig 1. El código fuente del programa


Al ejecutar el programa podemos observar el resultado como se muestra en las siguientes imágenes probando con diferentes patrones con los archivos etc/password y /etc/group respectivamente.


Fig 2. Una primera prueba con el archivo /etc/password

Fig 3. Una segunda prueba con el archivo /etc/password

Fig 4. Probando con el archivo /etc/group

sábado, 12 de noviembre de 2011

Utilizando JavaScript desde código ASP.NET

Actualmente es difícil construir una aplicación ASP.NET que no haga uso de las capacidades de JavaScript para realizar operaciones del lado del cliente o browser, operaciones que si fueran desarrolladas en su totalidad con la arquitectura ASP.NET serian demasiado costosas, basta recordar que ASP.NET es una arquitectura totalmente hecha para su uso del lado del servidor, por lo que hace uso de un mecanismo de Postback o de ida y vuelta entre los datos de la página solicitada por el cliente y por el servidor que proporciono la página, por lo que el mecanismo de Postback hace uso de uno de los recursos más valiosos de una red: el ancho de banda.

Durante ese viaje pueden ocurrir eventos que retarden o interrumpan la respuesta del servidor, causando una pérdida o una retrasmisión de los datos por parte del usuario resultando en una forma ineficiente de comunicación ya que ASP.NET reconstruye la página completa con todo su contenido en cada solicitud.

Para ayudar a no utilizar con frecuencia este mecanismo, hay que utilizar JavaScript en el cliente o browser como un complemento a las operaciones ASP.NET. Para utilizar JavaScript junto a ASP .NET, existe la clase ClientScriptManager la cual se programa mediante la propiedad ClientScript de la clase Page, la cual expone métodos que permiten incrustar código JavaScript dentro de la página ASP.NET.

Los métodos más comunes usados de esta clase son:

  1. RegisterClientScriptBlock: Incrusta el código JavaScript al inicio del formulario después de la etiqueta
    , genera dinámicamente el código JavaScript desde una cadena.
  2. RegisterStartupScript: Incrusta el código JavaScript en el final de la página, antes del cierre del formulario o sea antes del cierre de la etiqueta , por lo que se recomienda para operaciones con controles HTML o ASP.NET, ya que hace referencia a ellos una vez cargados.
  3. RegisterClientScriptInclude: sirve para ejecutar el código JavaScript que se guarda en un archivo externo (comúnmente con extensión .js) tiene dos cadenas como argumentos un nombre para identificar el script y el archivo que contiene el código JavaScript.

Como ejemplo mostraremos una página ASP.NET que utiliza dos listas de usuarios (ListBox) y dos botones (HTML input) que se utilizan para mover los usuarios de una lista hacia otra. Los eventos son controlados mediante código JavaScript, esto sin utilizar código JavaScript incrustado en la página HTML, sino que el código JavaScript se genera desde código ASP.NET. A continuación, el código Default.aspx:

El código ASPX/HTML de este ejemplo no crea funcionalidad alguna por lo que explicaremos la funcionalidad contenida en el código C#, en el código Default.aspx.cs.

Primero creamos el código JavaScript que tendra la funcionalidad para agregar los elementos de una lista hacia la otra, esto se logra con la función FuncCopyItem(string name, string source, string destiny) esta función recibe tres argumentos el nombre de la función JavaScript que se creará en el código HTML al solicitar la página y con la cuál se identificaran los eventos de los controles , el control ListBox fuente de donde inicialmente se tomarán los items y por último el control ListBox destino a donde se pondrán los items. Con la siguiente línea de código:

    ClientScriptManager cs = Page.ClientScript;

Obtenemos el objeto ClientScriptManager de la página, con él cual utilizaremos el metódo cs.RegisterStartupScript con sus parámetros correspondientes, algo importante por lo cuál usamos este metódo es por que para construir el código JavaScript utilizamos la propiedad ClientID del control ListBox, es decir el control debe existir obligatoriamente de lo contrario, cuando ASP .NET contruya la página contruirá el código JavaScript con estos parámetros nulos lo que causará un error no en la página ASP.NET sino en el código JavaScript cuando se llame para ejecutarse.

Fig 1 La vista del proyecto en Monodevelop.

Fig 2 Ejecutando la aplicación ASP.NET en Internet Explorer 9.0

Fig 3 Ejecutando la aplicación ASP.NET en Firefox.

Fig 4 Mostrado el código JavaScript en la página generada por ASP.NET.

jueves, 8 de septiembre de 2011

Ruteo Inter-VLAN en un Router Cisco utilizando Router-on-a-stick

Una VLAN es técnicamente un dominio de broadcast diferente, por lo que de forma predeterminada no pueden comunicarse entre sí, salvo se usen diferentes técnicas de ruteo inter-vlan cada una de los cuales tiene sus ventajas y sus desventajas, a continuación mostraré un ejemplo de una técnica llamada "Router-on-a-stick", que en resumen consiste en configurar una interfaz física de un Router para operar como un enlace troncal en el puerto de un switch, el Router efectua el ruteo intervlan de forma interna mediante el uso de subinterfaces, una subinterfaz es una interfaz virtual(vía software) que se crea en una interfaz física, por lo que se asocia cada subinterfaz con un número de VLAN, asi que podemos tener varias subinterfaces creadas en una misma interfaz física, lo cual presenta ventajas y desventajas que enumeramos a continuación.

Ventajas
  • Fácil de implementar solo se requiere crear una subinterfaz por cada VLAN en el Router.
  • Mucho más económica que tener un Router por VLAN.
  • Mucho mejor latencia que tener un Router por VLAN.
Desventajas
  • Los Routers son más lentos que los switches para ruteo inter-VLAN, lo ideal es tener un switch multicapa.
  • Si se necesita incrementar el número de puertos, entre más puertos requiera un Router más costoso resulta.
  • Estamos expuestos al buen funcionamiento de una sola interfaz física en el Router, esto es un único punto de fallo.

A continuación ejemplificaremos esta técnica con una práctica, los dispositivos son:

  • 4 PC's
  • 2 switches
  • 1 router
  • 1 access point
  • 1 laptop

Al colocarlos en el WorkSpace del Packet Tracer debe ver más o menos como en la siguiente imagen:


Para la creación de las VLAN es conveniente el empleo de VTP para no teclear doblemente la configuración,asi que utilizamos el switch 1 (SW1,el que va unido al Router) como servidor y el switch 2 (SW2 el que tiene el access point) como cliente, empezamos la configuración en el SW1, con los siguientes comandos:

Comandos para el switch 1

En el SW2 tecleamos los mismos comandos para crear las troncales, la variante es la forma en que obtenemos las VLAN's creadas en el SW1 por VTP.

Comandos para el switch 2

Para finalizar tecleamos los siguientes comandos en el router.

Comandos para el router

En la configuración IP de cada PC, debe de ponerse como gateway la ip de cada subinterfaz asociada a la VLAN dentro de la cual se encuentre configurada la PC.
Por ejemplo si una PC su ip es:192.168.20.2 y se encuentra en la VLAN 20 su gateway sera la IP 192.168.20.1 la cual se asigno a una subinterfaz asociada con la VLAN 20, como se muestra en las siguientes imágenes:




Igualmente si una PC su IP 192.168.30.2 es perteneciendo a la VLAN 30, entonces su gateway es la IP 192.168.30.1 que se asigno a la subinterfaz asociada con la VLAN 30


Aquí se muestra la comunicación inter-VLAN's.

miércoles, 7 de septiembre de 2011

Instalando Cisco Packet Tracer en OpenSuSe x64.

Cisco packet tracer es un simulador para dispositivos de redes en donde se realizan la prácticas de Cisco Networking Academy.
Este simulador existe para los sistemas operativos Linux Fedora y Ubuntu, en formato .deb y .rpm que se descarga como un archivo ejecutable con extensión .bin.
Como no existe una versión de Packet Tracer de 64 bits,una de las dependencias para la instalación, es la libreria ligpng de 32 bits, aunque la version de 64 bits de esta biblioteca se encuentra instalada de forma predeterminada Packet Tracer solicitara la versión de 32 bits, por lo cual es necesario instalar la bibloteca ligpng[X.X]-32bits, en el caso de los usuarios de Suse, esto se realiza con Yast.


Como se muestra en la siguiente imagen:
En este caso decidí instalarlo en su formato .rpm, una vez descargado procedí a instalarlo con los siguientes comandos:

$chmod +rx [PacketTracer532_i386_no_tutorials_installer-rpm.bin]
$su
#./[PacketTracer532_i386_no_tutorials_installer-rpm.bin]


Un problema que sucede con frecuencia cuando ejecutamos el programa, es la horrible visualización de las fuentes, esto debido a las siguientes razones:


  1. Cisco decidió utilizar sus propias bibliotecas QT para la ejecucción del programa, esto tiene sentido desde el punto de vista de que es un programa multiplaforma, por lo que evita que el usuario instale esa dependencia por separado, por ejemplo en el caso de Windows donde no se provee de forma predeterminada con tal requerimiento.

  2. La fuente predeterminada para los menus del programa es tahoma, la cuál es una fuente no génerica, si no se encuentra disponible la fuente de los menus se ven de una forma ilegible.



Para solucionar el primer punto, hay que instalar el paquete de desarrollo de QT en mí caso fue el libqt4-dev. Con lo cuál se arreglaran las fuentes de todo el workspace en especial la de los dispositivos de red.



sudo zypper in libqt4-dev

Los menús de Packet Tracer de una forma ilegible


Para solucionar el segundo punto hay que cambiar la fuente de los menús, siguiendo los siguientes pasos:


Ir a al submenú preferences en el menú options del menú principal, ahi se abrirá una ventana con una serie de pestañas, elegir entonces la pestaña font, ahi en la sección General Interface ubicamos el valor de File Menu como se muestra en la siguiente imagen.


Cambiamos la fuente de Tahoma por una fuente más génerica, en mí caso elegí Arial


Podemos apreciar el cambio en la legibilidad de la fuente de los menús del menú principal.


Enlaces adicionales donde se encuentra más información al respecto:


sábado, 30 de julio de 2011

Entendiendo Logging en Aplicaciones .NET con Log4net

Esta entrada se relaciona con esta entrada anterior, que trata también sobre el tema de Logging.
Log4net es opción altamente recomendable para la implementación del logging en las aplicaciones desarrolladas para .NET. Sobre todo cuando se necesita una solución más configurable y robusta que la proporcionada por las clases del ensamblado System.Diagnostics, que en comparación con log4net están en un nivel elemental, si necesitamos una herramienta que soporte diferentes fuentes de persistencia, que no afecte el desempeño de las aplicaciones y que sea transportable entre la implementación .NET de Microsoft y la del proyecto Mono.

Log4net es un Framework open source creado por la fundación Apache basado en la implementación de los servicios de logging existentes en log4j, un componente de logging usado durante años en los ecosistemas Java.
La arquitectura de Log4net puede resumirse en tres clases principales cada una encargada de una responsabilidad dentro del Framework y que se detalla a continuación:

  • Logger Captura la información para la bitácora.
  • Appender Publica la información hacia diversas fuentes de logging configuradas en la aplicación. Al menos debe definirse un Appender, el Appender predeterminado es el ConsoleAppender cual dirige su salida hacia una terminal de Consola.
  • Layout Se utiliza para darle formato haciendo legible cada salida de los distintos Appenders.

Para más información consultar http://logging.apache.org/log4j/1.2/manual.html aunque es para log4j la arquitectura es idéntica a log4net.

Como ejemplo del uso de log4net vamos a crear dos programas un cliente y un servidor los cuales se comunicarán entre sí, la clase ServerProgram es un servidor TCP que escucha en el puerto 6060 y la clase Program que es el cliente que al conectarse con el servidor, le solicita al usuario el nombre de un archivo de texto el cuál sera leído y cada línea de texto será enviada hacia el servidor. El programa cliente implementa todo el código básico para el manejo del logging con log4net.


Código de la clase ServerProgram
Código de la clase Program (cliente)

El archivo de configuración App.config en donde van las opciones de configuración de Log4net

En el archivo de configuración utilizamos el declarado en la siguiente sección
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="log.txt"/>
<appendToFile value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="[%date{dd-MM-yyyy HH:mm:ss}] [%level] %message %newline"/>
</layout>
</appender>
Declaración del componente principal para implementar los métodos del Logger.
static readonly log4net.ILog log = log4net.LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
carga la configuración del archivo de configuración para Log4net.
XmlConfigurator.Configure();
Escribir una excepción al log.
log.Error(ex.Message, ex);
Escribir información al log
log.Info("Ejecutando la aplicación en " + DateTime.Now.ToLongTimeString());
Compilando los programas:

Ejecutando el servidor

Ejecutando el cliente

Generando excepción de formato

Generando excepción de comunicación

Revisando el archivo de log, creado por log4net

miércoles, 29 de junio de 2011

File Upload con ASP.NET en Linux y Apache con HtmlInputFile (Html Control) y en IIS y Windows con FileUpload (Web Control).


Una de las operaciones más frecuentes de las aplicaciones web (Web applications) es la carga de archivos (file upload), que es la acción donde el usuario puede seleccionar un archivo de su computadora y mediante el uso de un formulario en una página web puede transferir el archivo desde el sistema de archivos local hacia el sistema de archivos del servidor donde se encuentre la página web.
ASP .NET tiene dos formas de hacer esta funcionalidad, una mediante un control HtmlInputFile la cual se ha soportado desde el Framework 1.1 y la otra mediante un control FileUpload la cual se soporta a partir del Framework 2.0.



A continuación mostramos el listado de un programa en ASP.NET como ejemplo de la implementación de publicación de documentos utilizando el control HtmlInputFile.


Listado 1.0 ASP.NET upload con un control HtmlInputFile



<%@ Page Language="C#" AutoEventWireup="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void Page_Load(object sender, EventArgs e)
{
}
//Version 1.1
protected void btnPublish_click(object sender, EventArgs args) {
try
{
string publishPath = ConfigurationSettings.AppSettings["publishPath"];
if(publishPath == null)
sspublishPath = "/home/martin/public_html/Downloads/";
if ((htmlinputFile.PostedFile != null) && (htmlinputFile.PostedFile.ContentLength > 0))
{
publish(htmlinputFile, publishPath);
lblmsg.ForeColor = System.Drawing.Color.Black;
lblmsg.Text = "Archivo públicado con éxito";
}
else
{
lblmsg.ForeColor = System.Drawing.Color.Red;
lblmsg.Text = "Falta archivo para publicar";
}
}
catch (Exception ex) {
lblmsg.ForeColor = System.Drawing.Color.Red;
lblmsg.Text = ex.Message;
}
}

public void publish(System.Web.UI.HtmlControls.HtmlInputFile inputFile,
string publishPath)
{
System.IO.FileInfo fi = new System.IO.FileInfo(inputFile.PostedFile.FileName);
string theFile = publishPath + fi.Name;
inputFile.PostedFile.SaveAs(theFile);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server" enctype="multipart/form-data">
<div>
<table width="33%">
<tr>
<td>
1-. Seleccione el archivo</td>
</tr>
<tr>
<td>
<input id="htmlinputFile" maxlength="5120" name="htmlinputFile" size="48"
type="file" runat="server" /></td>
</tr>
<tr>
<td>
2-. Pulse el botón publicar</td>
</tr>
<tr>
<td>
<asp:Button ID="btnPublish" runat="server" Text="Publicar"
OnClick="
btnPublish_click"/>
</td>
</tr>
</table>
<br />
<asp:Label ID="lblmsg" runat="server"></asp:Label>
</div>
</form>
</body>
</html>


Como muestra de la implementación ASP.NET con el control FileUpload, presentamos el siguiente listado.


Listado 2.0 ASP.NET Upload con un control FileUpload


<%@ Page Language="C#" AutoEventWireup="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
}
//Version 2.0 or above
public void btnPublish_Click(object sender,EventArgs args) {
try
{
string publishPath = System.Configuration.ConfigurationManager.AppSettings["publishPath"];
if (fupInputFile.HasFile && (fupInputFile.PostedFile.ContentLength > 0))
{
Publish(fupInputFile, publishPath);
lblmsg.ForeColor = System.Drawing.Color.Black;
lblmsg.Text = "Archivo públicado con éxito";
}
else
{
lblmsg.ForeColor = System.Drawing.Color.Red;
lblmsg.Text = "Falta archivo para publicar";
}
}
catch (Exception ex) {
lblmsg.ForeColor = System.Drawing.Color.Red;
lblmsg.Text = ex.Message;
}
}
public void Publish(FileUpload inputFile,
string publishPath) {
System.IO.FileInfo fi = new System.IO.FileInfo(inputFile.PostedFile.FileName);
string theFile = publishPath + fi.Name;
inputFile.PostedFile.SaveAs(theFile);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<table style="width:100%;">
<tr>
<td>
1-. Seleccione el archivo</td>
</tr>
<tr>
<td>
<asp:FileUpload ID="fupInputFile" runat="server" Width="522" />
</td>
</tr>
<tr>
<td>
2-. Pulse el botón publicar</td>
</tr>
<tr>
<td>
<asp:Button ID="btnPublish" runat="server" Text="Publicar"
OnClick="
btnPublish_Click"/>
</td>
</tr>
</table>
<br />
<asp:Label ID="lblmsg" runat="server"></asp:Label>
</div>
</form>
</body>
</html>

Para ambos casos el archivo de configuración web.config es el mismo, lo que cambia en ambos casos es el valor de la llave publishPath dentro de las etiquetas

<appSettings>
, ya que para el listado 1.0 que lo ejecutaremos en Linux utilizando Apache y Mono.
Por lo que el valor se establece en /home/martin/public_html/Downloads como se muestra en el web.config a continuación:



<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="publishPath" value="/home/martin/public_html/Downloads/"/>
</appSettings>
<connectionStrings/>
<system.web>
<compilation debug="true">
</compilation>
<authentication mode="Windows"/>
</system.web>
</configuration>

En el caso del listado 2.0 lo ejecutaremos en IIS 7.0 y Windows. Por lo que el valor se establece como se muestra en el web.config a continuación:


<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="publishPath" value="C:\inetpub\Downloads\"/>
</appSettings>
<connectionStrings/>
<system.web>
<compilation debug="true">
</compilation>
<authentication mode="Windows"/>
</system.web>
</configuration>

Para asignar el valor de la variable publishPath en el listado 1.0 con la siguiente línea:


string publishPath = ConfigurationSettings.AppSettings["publishPath"];

y para el listado 2.0 se asigna con la siguiente línea:


string publishPath = System.Configuration.ConfigurationManager.AppSettings["publishPath"];

Antes de ejecutar la página en Linux debemos habilitar con los permisos de escritura al directorio donde se guardaran los archivos, para hacerlo en Linux siga los siguientes pasos:


  1. El directorio donde se subiran los archivos debe tener los permisos de escritura para el grupo www.

  2. Si estamos como usuarios normales, cambiamos a una cuenta con privilegios de superusuario y establecemos y establecemos el grupo del directorio (en este ejemplo /home/martin/public_html/Downloads) como www con el siguiente comando:
    # chgrp www Downloads

  3. Ponemos permisos de escritura para el grupo con el siguiente comando:
    # chmod 775 Downloads




Estos comandos se muestran a continuación en la siguiente imagen.




Ahora configuramos la Web Application dentro del archivo httpd.conf del servidor Apache como se muestra en la siguiente imagen:



Para consultar como crear una aplicación Web en Apache revisar el siguiente documento:

Igualmente antes de ejecutar la página en Windows debemos de habilitar con los permisos necesarios el directorio del servidor donde vamos a guardar los documentos, en este ejemplo la ruta configurada como directorio de publicación es C:\inetpub\wwwroot\dowloads, por lo que debemos seguir los siguientes pasos:


  1. Hacer click derecho sobre el directorio, en la ventana Properties seleccionar al usuario IIS_IUSRS (el cuál es el usuario anónimo de IIS), presionar el botón “Edit” para abrir la ventana Permissions.


  2. En la ventana de Permissions en la lista inferior Permissions for IIS_IUSRS seleccionar la casilla con el permiso Write




Creamos la Web Application de forma que se muestre en IIS 7.0 como en la siguiente imagen:

Al ejecutar la página ASP.NET desde FireFox en Linux se mostrará como en las siguientes imágenes:



Al ejecutar la página ASP.NET desde Internet Explorer en Windows se verá como en las siguientes imágenes:



Un error frecuente tanto para la implementación con HtmlInputFile y FileUpload, es tratar de subir un archivo que tenga un tamaño mayor al máximo permitido por la petición al servidor Web (Request)
Para solucionar este error solo hay que agregar la siguiente línea al archivo de configuración, donde definimos el tamaño máximo en Kb del archivo que necesitamos publicar. Por ejemplo en el siguiente web.config se definió un tamaño máximo aproximado a 5 mbs (5120 kb).


<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="publishPath" value="C:\inetpub\Downloads\"/>
</appSettings>
<connectionStrings/>
<system.web>
<compilation debug="true">
</compilation>
<authentication mode="Windows"/>
<httpRuntime maxRequestLength="5120"/>
</system.web>
</configuration>

Para más información sobre este error consultar este enlace: HttpException Maximum Request Length.


sábado, 25 de junio de 2011

Utilizando Windows Management Instrumentation (WMI) con Microsoft .NET

Para las aplicaciones que necesiten implementar una solución de un inventario total o parcial del hardware de la computadora, existe una interfaz de programación llamada WMI (Windows Management Instrumentation) a la cual puede accederse mediante lenguajes scripting como VBScript, Perl,Power Shell o cualquier lenguaje diseñado para el .NET Framework que haga uso de los ensamblados System.Management y System.Management.Instrumentation respectivamente.

Windows Management Instrumentation (WMI) es un conjunto de extensiones del Modelo de drivers de Windows WDM (Windows Driver Model) que es un modelo uniforme de clases que representan los valores del hardware y sistema operativo de la computadora,WMI es además la implementación Microsoft de Web-Based Enterprise Management (WBEM) un estándar de la industria que agrupa tecnologías desarrolladas para unificar la administración de los ambientes de computo, por lo que WMI es compatible con WBEM y provee el soporte para el Common Information Model (CIM) que es el modelo que describe los objetos de administración.

Un inventario de hardware con WMI se realiza mediante búsquedas en el repositorio o base de datos de WMI utilizando un lenguaje de consultas conocido como WQL (WMI Query Language) para encontrar los valores de ciertas propiedades del Hardware. WQL es un subconjunto de SQL.

WMI trabaja dentro del contexto de un ensamblado, siendo el predeterminado root\cli que controla las propiedades y métodos que están disponibles en WMI, la seguridad para el WMI se configura a través del control WMI (wmimgmt.msc), de forma predeterminada los usuarios tienen permisos para consultar el proveedor WMI en una computadora local mediante el comando WMIC, desde la línea de comandos del command prompt.

A continuación las clases de un proyecto de consola que imprime información del hardware del equipo.

1-.Una clase PC que será el objeto de transporte

2-.Una clase PCManager que obtendrá algunos de los valores del Hardware para este ejemplo, mediante consultas WQL del repositorio WMI similar a las consultas SQL para en base de datos.

3-.Finalmente el programa principal que despliega información del equipo.

El resultado de la ejecución del programa se muestra en la siguiente imagen:

Los puntos claves del programa utilizados por la clase PCManager son

  1. Utilizar los ensamblados System.Management y System.Management.Instrumentation.
  2. Crear una instancia de la clase ManagementObjectSearcher
  3. Encapsular cada consulta dentro de la clase ObjectQuery
  4. Obtener los resultados de la búsqueda en una colección de ManagementObject representada por la clase ManagementObjectCollection, para iterar dentro de la colección e imprimir los valores.


También se puede mostrar información desde una página ASP.NET como en el siguiente listado:

El resultado de la ejecucción de la página:

martes, 31 de mayo de 2011

Entendiendo Logging en Aplicaciones para .NET Framework

El logging es un proceso recomendado durante la etapa de pruebas e indispensable durante la etapa de liberación o puesta en producción de aplicaciones de software, logging se refiere a la utilización de una bitácora, registro o log, donde guardemos la información de los diferentes eventos que genero la aplicación entre el tiempo de arranque y durante el tiempo de ejecución.
El registro o log debe proporcionarnos toda información necesaria para realizar con la aplicación las siguientes actividades:

  1. Mantener el rastro de todos sus estados (recording)
  2. Depurar (debugging)
  3. Auditar (audit)
  4. Diagnosticar su estado actual (tracing)

Un factor importante a considerar durante el logging es el performance de la aplicación ya que es un hecho que se incrementará el tiempo de las operaciones de escritura, sobre todo si el logging es requerido para una auditoría, este incremento en el performance se explica de la siguiente manera:

Si una operación del proceso de negocio emplea 5 segundos para ejecutarse y producir un resultado, con el logging necesitará 2 o 3 segundos adicionales para registrarse en el log, por lo que ahora el tiempo es de 7 u 8 segundos para el total de la operación.


El siguiente fragmento de código ilustra este factor:

try
{
//operación de negocio 5 segs.
var output = BussinessObject.ExecuteOperation();
//registro en el log 3 segs.
Logger.WriteLine(output);
//El tiempo total de la transacción es de 8 segs.

}catch(Exception e){

//No está incluído dentro de la transacción.
Logger.WriteLine(e.Message);

}

Hay muchas formas de implementar logging en las aplicaciones, esto varía dependiendo del tipo de aplicación y del requerimiento a satisfacer la forma más sencilla es mediante el uso de las clases contenidas en el ensamblado System.Diagnostics. específicamente con las implementaciones derivadas de la clase TraceListener las cuales son responsables de desplegar o de guardar los mensajes generados por las clases Trace y Debug, hay tres implementaciones de esta clase:

  1. TextWriterTraceListener escribe mensajes a cualquier clase que se derive de Stream
  2. EventLogTraceListener escribe los mensajes a el Event Viewer de Windows.
  3. DefaultTraceListener escribe los mensajes a la ventana de salida (Output window).

El siguiente listado muestra el uso de TextWriterTraceListener y EventLogTraceListener, la lógica del programa es simple, si el programa tiene permisos administrativos usará el event viewer como log, de lo contrario usará un archivo de texto, realizando un intercambio entre los Tracelisteners: EventLogTraceListener y TextWriterTraceListener respectivamente.

Al compilar el listado se debe de incluir la opción /d:TRACE como se muestra en la siguiente imagen:

Al ejecutar el programa mostrará un resultado como en la siguiente imagen:

Con el siguiente código el programa intercambia entre Listeners dependiendo si pertenece al grupo con permisos de administración o no.

Si no pertenece al grupo de administradores utiliza como log un archivo de texto log.txt caso contrario utiliza el Event Viewer (visor de eventos de Windows) como se muestra en la siguiente imagen:


Lo más recomendable para el logging es la utilización de componentes como el Logging Application Block de Microsoft o el Log4net de la fundación Apache.

Nuevo número de la revista de software libre Atix

Ha salido publicado un nuevo número de la revista de Software Libre Atix. Este es el número 19 de la publicación para su descarga, presionar en el enlace siguiente:

domingo, 24 de abril de 2011

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. Listing 1. La clase para acceso a datos.

  9. Agregamos al evento Clicked del Botón el metodo ExecuteQuery, cuyo código se muestra a continuación:
  10. Listing 2. Evento del botón executeQuery.

  11. El listado completo de la clase MainWindow se muestra a continuación:
  12. Listing 3. Clase principal de la interfaz GTK# Custom exception.

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.


sábado, 23 de abril de 2011

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.


martes, 19 de abril de 2011

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.

lunes, 21 de marzo de 2011

Referencias acerca del uso del Garbage Collector en .NET

Buscando referencias en cuanto al uso de los destructores en C# me encontré estos fragmentos del libro Advanced C# Programming de Paul Kimmel donde en el capítulo 1 pag 18 habla acerca de la destrucción no determinística y Garbage Collector, fragmento que copio tal cuál se encuentra en el libro:


C# uses non-deterministic destruction. The CLR implements a garbage collector that cleans up memory when objects are no longer used. This means that you don’t have to worry as much about destructors in C# as you do in C++ or Delphi.
The garbage collector will call the destructor for your objects when they are no longer needed. The destructor will call any Finalize method. You can force garbage collection by calling GC.Collect, but this is not a recommended process. The garbage collector suspends any running threads, which can cause performance problems. Besides, the garbage collector will do a good job of determining when to run.


De nuevo en el en el capítulo 3 pag 76, recalca la importancia de que no es una buena práctica, fragmento que copio tal cuál se encuentra en el libro



Control Dispose Methods C# is a .NET language. I state the obvious as a way to segue into a subject that may not be obvios. Languages like Object Pascal or C++ use deterministic construction and destruction. This means that the programmer is responsible for both creating and destroying objects.
.NET employs non-deterministic destruction.This means that the programmer is not responsible for destroying objects.The gargabe collector will clean up objects for you. As a result, you will write code that invokes the new operator, but there is no equivalent free operator.
NOTE: You can invoke the garbage collector explicitly by calling GC.Collect, but this is not a recommended practice.


Aunque la biblioteca de la universidad tiene la edición 2002 y no sé si en las ediciones actuales haya cambiado, considero que es interesante lo que menciona además que un amigo y compañero de trabajo me pregunto hace algunos años si era posible invocar a voluntad el Garbage Collector a lo cual respondí por lógica que sí porque ya había visto la clase System.GC y algo había leído algo al respecto pero en ese momento no sabía bien acerca de sus implicaciones y no había recordado la fuente.


domingo, 20 de marzo de 2011

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


domingo, 27 de febrero de 2011

Cambiando la resolución de pantalla de forma permanente en OpenSuse 11.3

Pues teniendo desde hace un par de meses OpenSuse 11.3 en mí nueva portátil (Dell Inspiron 14), algo que ya había leído pero no había hecho era cambiar la resolución de la pantalla de forma permanente.
Ya que de forma predeterminada el sistema establecía la resolución 1366x768 resolución que para mostrar ciertas gráficas en proyectores no era apropiada, por lo que siempre cambiaba la resolución de forma manual a una resolución estándar de 1024x768, algo que en versiones anteriores de OpenSuse se realizaba con Sax2 y se conservaba después de reiniciar o apagar el equipo cosa que en esta versión no ocurre.


Leyendo en la documentación de OpenSuse encuentro que esta versión no incluye Sax2 ni sus derivados como (Sax2-vesa), por lo que ese cambio debe hacerse de forma programática.


El procedimiento se describe en este enlace .
A continuación pongo algunas anotaciones con imágnes en caso de que el enlace/post cambie y para que tenga manera de recordarlo.



  1. Como root cambiamos al directorio /etc/X11/xorg.conf.d/
    # cd /etc/X11/xorg.conf.d/

  2. Sacamos una copia de seguridad del archivo 50-screen.conf
    # cp 50-screen.conf 50-screen.conf.bak


  3. Vemos las resoluciones soportadas en el menú "Preferencias del sistema" del inicio de KDE.



  4. Editamos el archivo, agregando las siguientes líneas y colocando en primer lugar la resolución que necesitamos de forma permanente.
    # vi 50-screen.conf
    Section "Screen"
    Identifier "Default Screen"
    Device "Default Device"

    ##Doesn't help for radeon/radeonhd drivers;use magic in
    ##50-device.conf instead
    Monitor "Default Monitor"

    SubSection "Display"
    modes "1024x768" "800x600" "640x480"
    EndSubSection

    EndSection



  5. Reiniciamos el equipo para probar el cambio.

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.

viernes, 14 de enero de 2011

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();