martes, 30 de noviembre de 2010

Notas acerca de direcciones IP y la dirección IP en .NET

Las direcciones IP se dividen en tres clases generales (A, B, C) y dos especializadas que son utilizadas para propósitos experimentales (D, E). Las direcciones IP se representan por cuatro octetos u ocho bits, separados por puntos, así como la dirección MAC nos proporciona identificación, la dirección IP nos da ubicación.

Cada dirección IP se compone de dos campos un campo de red y un campo de host. El tamaño de cada uno de esos campos varía según la clase:
Para la clase A tenemos el primer octeto para identificar la red y los restantes tres para identificar al host.
Para la clase B tenemos los dos primeros octetos para identificar la red y los dos restantes para identificar al host.
Para la clase C tenemos los tres primeros octetos para identificar al host y el último octeto para identificar al host.
El primer octeto en decimal siempre nos indica la clase a la que pertenece una red, dependiendo de su valor en decimal dentro de los siguientes rangos:


  • 0 a 127 es clase A

  • 128 a 191 es clase B

  • 192 a 223 es clase C


Aquí si observamos el inicio del rango es par y el final es impar.
En la clase A, la dirección IP 127.0.0.1 se reserva como dirección de loopback.
Existen además tipos reservados de IP como por ejemplo si los octetos de host son puestos en 0 (cero) esa dirección IP identifica a la red o si todos los octetos de host son puestos en 1 o 255 en decimal esa dirección IP es una dirección IP de Broadcast.

Una manera de identificar los tipos de red es buscar la posición del bit 0 (cero) dentro del primer octeto, la reglas son:
Si el primer bit es 0 (cero) la dirección es clase A, si el segundo bit es 0 (cero) la dirección es clase B, si el tercer bit es 0 (cero) entonces es clase C. Como en el siguiente esquema:


clase A | 0 1 1 1 1 1 1 1
---------+-----------------
clase B | 1 0 1 1 1 1 1 1
---------+----------------
clase C | 1 1 0 1 1 1 1 1


IP local en .NET

.Net tiene diversas clases dentro del ensamblado System.Net para el manejo de direcciones IP mostraremos el uso básico de esas clases para obtener la dirección o las direcciones IP de la máquina en donde se ejecute el siguiente listado.

Para acceder a las clases de red, primeramente hacemos referencia a los ensamblados


using System.Net;
using System.Net.Sockets;

En la siguiente línea

IPHostEntry ipinfo = Dns.GetHostByName(Dns.GetHostName());

Utilizamos el método GetHostByName de la clase Dns el cual nos devuelve un objeto IPHostEntry del cual utilizamos la propiedad AddressList que es una lista de objetos del tipo IPAddress que representa cada IP de la máquina en caso de tener más de una interface de red y que recorremos con un ciclo utilizando el método GetAddressBytes() para obtener los octetos como un arreglo.

foreach(IPAddress ip in ipinfo.AddressList){
byte[] b = ip.GetAddressBytes();
}

Por último utilizamos las propiedades estáticas IPAddress.Loopback y IPAddress.Broadcast para imprimir la dirección Loopback y de Broadcast respectivamente.
Al compilar y ejecutar el programa obtendremos algo similar a lo que se muestra en la siguiente imagen:


domingo, 31 de octubre de 2010

Uso de unchecked en C#

En este post mencione sobre algunos ejemplos que tome del libroJava Puzzlers: Traps, Pitfalls, and Corner Cases de Joshua Bloch y Neal Gafter publicado por Addison Wesley Professional en el año 2005 donde vienen curiosidades y trucos acerca de la programación con Java, Los siguientes ejemplos se encuentran en el libro y requieren el uso en C# de los operadores checked y unchecked para controlar la comprobación de overflow en operaciones aritméticas y conversiones.

Siempre que trabajemos con operaciones numéricas o con conversiones en nuestros programas hay posibilidades de que suceda un overflow (desbordamiento) cuando el resultado de dicha operación sobrepase la capacidad mínima o máxima de la variable que usemos para contener ese resultado. Los siguientes listados ejemplifican el uso de estos operadores.

Fig 1. El primer ejemplo sin la palabra unchecked.

Fig 2. El segundo ejemplo sin la palabra unchecked.


En el primer caso el compilador envía el siguiente error:
Puzzle4.cs(12,50): error CS0220: The operation overflows at compile time in checked mode


Para el segundo caso el mensaje es similar

Puzzle6.cs(10,30): error CS0221: Constant value `-1' cannot be converted to a `byte' (use `unchecked' syntax to override) Compilation failed: 1 error(s), 0 warnings


Debido a que en los dos listados el overflow puede ser comprobado en tiempo de compilación, en C# de forma predeterminada todo el código asignado a constantes es comprobado aunque este dentro de un bloque unchecked, y para las variables si el overflow ocurre en tiempo de ejecución el programa lanza una OverflowException excepto que sea suprimida usando unchecked.

Por lo tanto para compilar los listados, debemos de usar un bloque unchecked en la asignación de las siguientes variables en el primer listado:


unchecked{
const long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
const long MILIS_PER_DAY = 24 * 60 * 60 * 1000;
resp = (MICROS_PER_DAY / MILIS_PER_DAY);
}

Y un bloque similar en el segundo listado.


unchecked
{
Console.WriteLine((int)(char)(byte)-1);
}

El uso de unchecked en el primer listado ocasiona que no se produzca una excepción aunque ocurra el overflow esto siempre ocasiona que los valores sean truncados, por lo que el resultado de la ejecucción de este programa no es lo esperado.


Para solucionar por completo el código del listado 1 debemos agregar el caracter L al final del primer término (en este ejemplo el número 24), así toda las subsecuentes expresiones seran de tipo long.
El bloque de código se muestra a continuación.



const long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
const long MILIS_PER_DAY = 24L * 60 * 60 * 1000;
resp = (MICROS_PER_DAY / MILIS_PER_DAY);

El código final del ejemplo 1 utilizando la palabra unchecked

El código final del ejemplo 2 utilizando la palabra unchecked


La salida al ejecutar el listado 1 es

y la salida al ejecutar el listado 2 es

lunes, 25 de octubre de 2010

Expresiones Lambda (Lambda Expressions) con C#

Las expresiones lambda provienen del cálculo lambda (lambda calculus) desarrollado por Alonzo Church en los años 1930’s como una notación para representar todas las funciones computables equivalentes a una máquina de Turing, todos los lenguajes funcionales pueden ser vistos como una variante sintáctica del cálculo lambda.
Las expresiones Lambda son útiles para sintetizar funciones con pocos parámetros que regresan algún valor, esta expresión consiste básicamente en una regla de sustitución que expresa tal cual una función o sea un mapeo de los elementos del conjunto dominio a los elementos de un codominio por ejemplo en la siguiente expresión:



cuadrado : integer → integer donde cuadrado(n) = n²

Aunque C# no utiliza los símbolos de la notación matemática lambda, el operador lambda es => que significa “tiende a” o “va hacia a”, la estructura de una expresión lambda en C# es:



(Argumentos de entrada) => (salida al procesarlos)

Veamos algunos ejemplos:


La salida del programa es la siguiente imagen

Ahora un ejemplo con funciones estadísticas:

la salida de este ejemplo es la siguiente imagen


Es importante saber que es el tipo delegate que dicta el tipo de los parámetros de entrada y de salida.


domingo, 3 de octubre de 2010

Conversiones y curiosidades acerca de C#

En el libro Java Puzzlers: Traps, Pitfalls, and Corner Cases de Joshua Bloch y Neal Gafter publicado por Addison Wesley Professional en el año 2005 encontré ciertas curiosidades y trucos acerca de la programación en Java que me llamaron la atención, los autores explican la razón de tales escollos por lo que tome algunos ejemplos del libro para programarlos con C# y ver si obtendría los mismos resultados que sus contrapartes en Java.

Aquí algunos ejemplos del libro con las mismas preguntas, la diferencia únicamente es la implementación de Java a C#.

1-. En el siguiente programa ¿Es en todos los casos seguro que el método IsOdd determine correctamente si el número entero es par o no?

2-.¿Qué valor imprime el siguiente programa?

3-. ¿Cuál es el resultado del siguiente programa?

Analicemos cada uno de los ejemplos.

Ejemplo 1

Observaciones Al ejecutar el programa y pasarle un número entero como argumento desde la línea de comandos al parecer el programa determina si ese número es par o no, como en las siguientes imagen.

Pero el método que determina si el número es par o impar falla al pasarle un número negativo par o impar, esto siendo que toma como parámetro un entero y la mitad de los valores del tipo entero son negativos, el método supone que los residuos son únicamente positivos siendo que cuando la operación del residuo regresa un número que no es cero conserva el signo del dividendo.

La solución entonces es cambiar el método para que la comparación en vez de quedar igual a uno cambie a diferente a cero


static bool IsOdd(int i)
{
return i % 2 != 0;
}

La siguiente imagen nos muestra el resultado:

Ejemplo 2


Observaciones Este ejemplo se refiere a una mala práctica de programación, si examinamos el código puede que no nos percatemos que el último digito del segundo sumando en lugar de ser el número uno (1) es la letra l (ele) minúscula, por lo que una de las buenas prácticas de programación señaladas en el libro es no utilizar la letra l (ele) minúscula para indicar un valor numérico de tipo long o como variable.



Console.WriteLine(12345 + 5432l);

En todo caso el compilador de C# nos lanza la advertencia al compilar el programa,


Puzzle2.cs(9,34): warning CS0078: The 'l' suffix is easily
confused with the digit '1' (use 'L' for clarity)
Compilation succeeded - 1 warning(s)

que nos recomienda usar siempre la letra mayúscula para evitar confusiones, como se muestra en la siguiente imagen.


Ejemplo 3

Observaciones si examinamos el código del programa, al ejecutarlo debería de imprimir XX o sea dos veces el carácter ‘X’, un carácter por cada expresión por expresión, sin embargo al ejecutar el programa imprime 8888 como en la siguiente imagen:


Esto se debe a ciertas reglas del operador ternario u operador condicional (condicional operator) donde el primer operando debe ser de tipo bool que se cumple en el caso de ambas expresiones, la diferencia está en el segundo y tercer operador donde las reglas son:

  1. Si los dos operadores son del mismo tipo la expresión devuelve ese tipo.
  2. Si hay una conversión implícita del segundo al tercero pero no del tercero al segundo entonces la expresión devuelve el tipo del tercer operador.
  3. Si hay una conversión implícita del tercero al segundo pero no del segundo al tercero entonces la expresión devuelve el tipo del segundo operador.

En el ejemplo 3 en la primera expresión existe la conversión implícita de char a int por lo que valor de la expresión es de tipo int y a imprimir es de tipo carácter se cumple la primera regla y en la segunda expresión no existe conversión implícita de int a char por lo se cumple la tercera regla.

En ambos casos es el equivalente de

Console.Write((int)x);
Para eliminar la confusión cambiemos el código a una conversión explicita:

El resultado es el esperado como se muestra en la siguiente imagen:

domingo, 19 de septiembre de 2010

Trabajando con Store Procedures PL/pgSQL en PostgreSQL

Los lenguajes de procedimientos (procedural languages) han extendido la funcionalidad de las bases de datos proporcionando al lenguaje SQL cierto flujo de control similar al de un lenguaje de programación.

Cada fabricante tiene su propia implementación de un lenguaje de procedimiento basado en SQL, así Microsoft SQL Server tiene Transact-SQL, Oracle tiene PL/SQL y así sucesivamente una lista de bases de datos con su correspondiente lenguaje de procedimiento. En el caso de PostgreSQL se tienen varios lenguajes que pueden usarse como lenguajes de procedimiento entre ellos tenemos a PL/Tcl, PL/Perl, PL/Python,C y como opción predeterminada PL/pgSQL.

Las ventajas de ejecutar funciones del lado del servidor o Store Procedures con PL/pgSQL son las siguientes:

  1. Extensibilidad: PL/pgsql es como un lenguaje de programación incluye la asignación y evaluación de variables y la posibilidad de hacer iteraciones y cálculos más complejos que con SQL.
  2. Seguridad: Ayuda a evitar ciertos ataques con SQL Injection ya que al utilizar parámetros evita la construcción de comandos SQL utilizando la concatenación de cadenas.
  3. Rapidez: Son ejecutados más rápidamente que las consultas SQL individuales ya que después de la primera ejecución el plan de ejecución se mantiene en memoria y el código no tiene que ser analizado ni optimizado nuevamente.
  4. Programación modular: similar a los procedimientos y funciones en los lenguajes de programación, lo que evita que se tengan planas de sentencias SQL.
  5. Reutilización: de código una función puede ejecutarse dentro de distintos Store Procedures.
  6. Rendimiento: un Store Procedure puede contener decenas de sentencias SQL que son ejecutadas como una sola unidad de golpe, a diferencia de las sentencias SQL individuales donde hay que esperar a que cada una sea procesada.

Mediante los siguientes ejemplos mostraremos el uso de Store Procedures utilizando PL/pgSQL.

Creamos una base de datos de ejemplo llamada Catalogs con el siguiente comando desde el Shell.

    $ createdb Catalogs
Fig 1. Creando la base de datos de ejemplo

Revisamos los lenguajes de procedimiento instalados en la base de datos, revisamos que PL/pgSQL se encuentre instalado con el siguiente comando.

    $ createlang -l Catalogs
Fig 2. Revisando la instalación del lenguaje PLSQL

Si no se encuentra, entonces ejecutamos el siguiente comando para instalarlo, esto siempre como administrador del servidor:

    $ createlang –U postgres plpgsql Catalogs

Si está instalado entonces abrimos un editor de texto y creamos un archivo llamado catalogs.sql donde escribiremos los comandos para crear las tablas de ejemplo y los Store Procedures para administrar los registros de cada una de las tablas.

Para la creación de las tablas escribimos lo siguiente:

En acuerdo con la llave foránea definida en cada tabla, debe existir un país para poder crear un estado, así mismo debe de existir un estado para poder crear una ciudad, entonces creamos unos registros en la tabla países

Fig 3. Insertando los registros en la tabla

Supongamos que estas tablas van a utilizarse en un sistema donde sea obligatorio que los nombres de país, estado y ciudad, se almacenen teniendo la primera letra mayúscula o en notación Camel Case,(en este caso los países quedaron guardados con letras minúsculas de manera intencional, con el fin de mostrar un Store Procedure).

Creamos entonces una función para aplicar esta regla a los datos de la tabla countries.

La función se define con el siguiente código:

Lo aplicamos de la siguiente manera para actualizar los registros.

Fig 4. Actualizando los registros utilizando la función UpperCamelCase

Una vez creada en el servidor se encuentra disponible para cualquier transformación que queramos aplicar sobre cualquier cadena.

Fig 5. Ejecutando la función UpperCamelCase

Ahora escribiremos las funciones para insertar registros en cada una de las tablas.

Básicamente la estructura de un Store Procedure es la siguiente:

CREATE FUNCTION [nombre de la función] ([parámetros separados por comas]) RETURNS [el tipo de dato que regresa] AS
'DECLARE aquí se definen las variables que se usarán.
BEGIN indica el inicio de la función.
SELECT INTO este comando permite que los resultados de las consultas sean asignados a variables. 
(no debe de confundirse con SELECT [columnas] INTO)
RETURN Sale de la función y regresa el tipo de dato que se declaro después de la palabra RETURNS del CREATE FUNCTION
END indica el fin de la función
' LANGUAGE indica con que lenguaje esta escrita la función, puede ser un lenguaje de procedimiento 
(plpgsql) o de consulta (SQL).

Vemos que en cada Store Procedure, reutiliza la función UpperCamelCase(varchar) que habíamos previamente creado.

Esto porque un Store Procedure puede llamar a otro Store Procedure que se encuentre disponible.

En las siguientes imágenes los resultados de la ejecución de cada Store Procedure.

Fig 6. Ejecucción del procedimiento InsertState

Fig 7. Ejecucción del procedimiento InsertCity

Fig 8. Comprobando la aplicación de los procedimientos en los datos

martes, 7 de septiembre de 2010

Utilizando los objetos NpgsqlConnection y NpgConnectionStringBuilder para PostgreSQL con MonoDevelop

Hoy día es difícil imaginarse un sistema informático que no haga uso de fuente de datos para persistir información.
Entre estas fuentes de datos se encuentran:
  • Sin estructura: Archivos que no tienen un orden lógico. (Cartas, memos)
  • Estructurado, sin jerarquía: Contienen datos agrupados por separadores o indicadores de inicio y fin (archivos de acceso secuencial, archivos separados por tabuladores ó comas)
  • Jerárquica: tienen una estructura de nodos anidados. (XML)
  • Bases de datos relacionales:
  • Objetos: Los datos están organizados como objetos.

Debido a esta variedad, las clases de ADO para acceder y extraer cuentan con un diseño independiente y portable de la implementación de la fuente de datos que se utilice.
Desde luego, primeramente debemos tener acceso a la fuente de datos antes de ejecutar operaciones de consulta o modificación.
Para lograr este propósito usamos un objeto proveedor de conexión especifico según la fuente de datos a utilizar, cada uno de estos objetos son equivalentes en funcionalidades generales por derivar de la clase DBConnection.
Aunque estos objetos son equivalentes en la funcionalidad general, cada uno tiene código específico para su fuente de datos, como se muestra en la tabla siguiente.


+-----------------+-------------------+
| Fuente de datos |Objeto de conexión |
+-----------------+-------------------+
| SQL Server | SqlConnection |
+-----------------+-------------------+
| Suportan OLE DB | OleDbConnection |
+-----------------+-------------------+
| Oracle | Oracleconnection* |
+-----------------+-------------------+
| PostgreSQL | NpgsqlConnection |
+-----------------+-------------------+
*Depende de que el cliente de Oracle se encuentre instalado.

El objeto NpgsqlConnection


Un objeto conexión representa una conexión física a una fuente de datos, por lo que una de las mejores recomendaciones es conectarse y cerrar las conexiones abiertas en cuanto dejen de utilizarse.
ConnectionStrings (Cadenas de conexión)
Antes de trabajar con cualquiera de los objetos de conexión es indispensable proporcionarle la Connection String (cadena de conexión) , esta Connection String es propia de cada objeto Connection y cada objeto Connection es propio de cada fuente de datos con la que trabajemos.
La cadena de conexión es una serie de parámetros y valores separados por (;) y aunque cada Connection String cambie según el proveedor de Base de datos, hay ciertos parámetros que son siempre requeridos, como:



+---------------------------+-------------------------------------------------+
|Data Source o Server | El lugar donde se encuentra la fuente de datos: |
| servidor, máquina, lugar de red, IP, directorio,|
| archivo. |
+---------------------------+-------------------------------------------------+
DataBase o Initial Catalog | El nombre de la base de datos a usar. |
+---------------------------+-------------------------------------------------+
|User ID | El usuario para acceder. |
+---------------------------+-------------------------------------------------+
Password | El password del usuario para aceder |
+---------------------------+-------------------------------------------------+
Integrated Security | Si es true se utiliza la seguridad de Windows
| para acceder, si es false se debe de proporcionar
| el user y password para acceder.
+---------------------------+-------------------------------------------------+
Timeout o Connection Timeout| El tiempo que debe esperar la aplicación para |
| que el servidor le asigne una conexión. |
| El valor predeterminado es de 15 segundos |
+---------------------------+-------------------------------------------------+
Pooling | Crea un pool de conexiones para la cadena de |
| conexión si no existe, caso contrario |
| asigna una conexión de un pool existente. |
+---------------------------+-------------------------------------------------+
MinPoolSize | Número mínimo de conexiones por pool, valor |
| predeterminado 1 |
+---------------------------+-------------------------------------------------+
MaxPoolSize | Número máximo de conexiones por pool, valor |
| máximo permitido 100 |
+---------------------------+-------------------------------------------------+

El sitio Connection Strings.com contiene ejemplos y una amplia referencia a cada uno de los parámetros y valores según la fuente de datos.

El objeto NpgsqlConnectionStringBuilder

Hay una clase que nos ayuda a evitar errores de sintaxis al momento de construir cadenas de conexión, esto para no tener recordar cada una de las opciones en el caso de trabajar con diferentes bases de datos. Esta clase es similar a las clases Connection, hay una clase DbConnectionStringBuilder de donde surgen las objetos ConnectionStringBuilder específicos para cada cadena de conexión de cada objeto Connection.
Derivados de la clase DbConnectionStringBuilder, existe la clases NpgsqlConnectionStringBuilder la cual encapsula una ConnectionString (cadena de conexión) para PostgreSQL, la cual demostraremos en el siguiente programa junto con el uso de la clase NpgsqlConnection respectivamente.


Abrimos MonoDevelop, creamos una nueva solución GTK# y agregamos unos controles al formulario para que su aspecto luzca como en la siguiente imagen.


Como utilizaremos el proveedor de datos de PostgreSQL para .NET debemos agregarlo a la solución, hacemos click derecho en la solución(recomiendo la versión 2.x).

Aparecerá la ventana para agregar/quitar las referencias a los ensamblados instalados en el GAC o para buscarlos en el sistema de archivos.


Una vez agregado correctamente, se mostrará el ensamblado en la solución.

Dentro del método para dar funcionalidad al botón de aceptar, mostramos la utilización de la clase NpgsqlConnectionStringBuilder como ayuda para crear la cadena de conexión.

También dentro de este método tenemos el código para la creación de la conexión al servidor.


using(NpgsqlConnection conn = new NpgsqlConnection(connString.ToString())){
conn.Open();
if(conn.State == System.Data.ConnectionState.Open)
MessageBox("Conexión exitosa",MessageType.Info);
}

Si descargamos el código completo del proyecto, al compilarlo correctamente y ejecutarlo,nos pedirá teclear los parámetros para una conexión hacia un servidor PostgreSQL.

Si los parámetros son correctos y el servidor se encuentra disponible entonces la aplicación mostrará el mensaje siguiente:

sábado, 21 de agosto de 2010

Utilizando la clase FtpWebRequest para un cliente básico FTP con MonoDevelop

Una de las tareas más habituales que existen en el tema de interacción entre sistemas es la copia de archivos de una máquina a otra, existen distintos mecanismos según el tipo de sistema operativo que se disponga entre la máquina destino y la máquina fuente, por ejemplo si se trata de sistemas UNIX/Gnu/Linux podemos utilizar el comando rcp o scp si se trata del servicio SSH.
Para el caso de copiar archivos entre sistemas operativos distintos la opción más común es utilizar el protocolo FTP (File Transfer Protocol) que es un protocolo orientado al usuario que hace uso de comandos para realizar operaciones con archivos en el servidor donde se establece la comunicación y para el cual .NET nos ofrece la clase FtpWebRequest que encapsula toda la funcionalidad de un cliente FTP y de los comandos propios del protocolo mediante los campos de la clase WebRequestMethods.Ftp.



+====================+========+==========================================+
| OPERACIÓN |COMANDO | DESCRIPCIÓN |
+====================+========+==========================================+
|AppendFile |APPE | Anexa un archivo a un archivo existente. |
+--------------------+--------+------------------------------------------+
|DeleteFile | DELE | Elimina un archivo existente. |
+--------------------+--------+------------------------------------------+
|DownloadFile | RETR | Descarga un archivo existente. |
+--------------------+--------+------------------------------------------+
|GetDateTimestamp | MDTM | Obtiene el date-time stamp de un archivo.|
+--------------------+--------+------------------------------------------+
|GetFileSize | SIZE | Obtiene el tamaño de un archivo. |
+--------------------+--------+------------------------------------------+
|ListDirectory | NLIST | obtiene un listado corto de los archivos |
| de un directorio en el servidor. |
+--------------------+---------------------------------------------------+
|ListDirectoryDetails| LIST | Obtiene un listado detallado de los |
archivos de un directorio en el servidor.|
+--------------------+--------+------------------------------------------+
|MakeDirectory | MKD | Crea un directorio en el servidor. |
+----------------------+------+-----------------------------------------+
|PrintWorkingDirectory | PWD | Imprime el nombre del directorio |
de trabajo. |
+----------------------+------+-----------------------------------------+
|RemoveDirectory | RMD | Elimina un directorio. |
+----------------------+------+-----------------------------------------+
|Rename | RENAME| Renombra un directorio. |
+----------------------+-------+----------------------------------------+
|UploadFile | STOR | Envia un archivo al servidor. |
+------------------------+-----+----------------------------------------+
|UploadFileWithUniqueName|STOU |Envia un archivo con |
un nombre unico al servidor. |
+------------------------+-----+----------------------------------------+


Y que ejemplificaremos a continuación programando un cliente FTP básico con MonoDevelop.
Ejecutamos MonoDevelop y diseñamos un formulario GTK# como se muestra en la siguiente imagen:


Agregamos una nueva clase a nuestro proyecto con el nombre de FtpDAO, que es donde se encontrarán los métodos que darán la funcionalidad a nuestro formulario.
En esta clase hacemos referencia a los siguientes ensamblados:


using System.IO;
using System.Net;

Y completamos la funcionalidad de la clase con los siguientes métodos.
Para listar los archivos del directorio en el servidor, escribimos el siguiente método:

Que nos regresa la lista de los archivos en un objeto ListStore que servirá de modelo para nuestra interfaz gráfica.
Con el siguiente código establecemos un Uri con la dirección IP o Host y con el directorio al cuál accedemos.


string.Format("ftp://{0}/{1}/",txtServer.Text,txtDir.Text);

La clase Uri sirve para encapsular un URI (Uniform Resource Identifier) que es una manera de identificar
Sin ambigüedades un recurso en Internet, puede ser un archivo, una dirección email o una dirección IP con su protocolo. Hay dos tipos de URIs: URL (Universal Resource Location) o URN (Universal Resource Names), en C# la clase Uri nos brinda todos los métodos y propiedades para el manejo de URI's.
En nuestro ejemplo será la URL del servidor de FTP, como se utiliza con la línea.
Uri serverUri = new Uri(string.Format("ftp://{0}/{1}/",txtServer.Text,txtDir.Text));

Donde concatenamos el protocolo con la IP o nombre del servidor y el directorio donde mostramos el listado, para después seleccionar el archivo a descargar.

C# WebRequest y WebResponse


La clase System.Net.WebRequest representa una petición al servidor y la clase System.Net.WebResponse representa la respuesta del servidor como un flujo de datos o StreamReader.
Usamos el método estático Create de WebRequest para solicitar el recurso del servidor dependiendo del URI que le pasemos como parámetro.

_ftprequest = (FtpWebRequest)WebRequest.Create(serverUri);

Usamos el método GetResponse para obtener la respuesta como un flujo de datos y asociándola a un objeto StreamReader.

using(FtpWebResponse listResponse = (FtpWebResponse)_ftprequest.GetResponse()){
using(StreamReader reader = new StreamReader(listResponse.GetResponseStream())){

Podemos establecer el timeout de la respuesta en milisegundos con la propiedad timeout que tiene un valor predeterminado de 10000.
La funcionalidad de descargar un archivo se la damos con el siguiente método.


Al construir y ejecutar la aplicación veremos los resultados como en las siguientes imágenes.

Al oprimir el botón Aceptar después de teclear la IP, el directorio, el usuario y el password, si son válidos para el servidor se muestra el listado de los archivos.

Si activamos la casilla de Listado detallado mostrará el listado detallado de los archivos.

En caso de que ocurra un error en la conexión con el servidor, se mostrará un mensaje con la excepción correspondiente.

Si seleccionamos un archivo de la lista de archivos y pulsamos el botón guardar se solicitará el archivo del servidor y se guardará en el disco duro en el directorio donde se ejecute la aplicación.

En la siguiente imagen la aplicación se conecta a un sitio público habilitando la casilla de autenticación anónima.

jueves, 5 de agosto de 2010

Utilizando la clase WindowsPrincipal con MonoDevelop

En este post Conceptos Básicos de seguridad en .NET (parte II) muestro un par de programas ejemplificando acerca de la utilización de la clase WindowsPrincipal. Esta clase representa la información de autenticación y de autorización de una entidad dentro del sistema.
Estos ejemplos pueden compilarse y ejecutarse en Linux, en este caso lo hice en un sistema operativo OpenSuse versión 11.1, con el compilador 2.6.7 y el runtime de mono versión 2.6.7, como se muestra en la siguiente imagen:



El primero de los dos ejemplos lo compilamos y lo ejecutamos mostrando el resultado como en la siguiente imagen:



En la siguiente imagen mostramos el resultado si lo ejecutamos como el superusuario root.


En el caso del segundo ejemplo modificamos el código y cambiamos la interfaz de consola por una interfaz gráfica utilizando el diseñador GTK# de MonoDevelop, siguiendo los siguientes pasos:



  1. Creamos una solución con un proyecto GTK# 2.0 en Monodevelop como en la siguiente imagen:


  2. Modificamos la apariencia del formulario, agregamos dos botones btnEnter, btnClose y un textview nombrado txtInfo para que el formulario se vea como en la siguiente imagen:


  3. Agregamos el método para el evento Clicked del botón btnEnterutilizando la pestaña señales en la ventana de propiedades, seleccionamos el evento y hacemos doble click para que MonoDevelop genere el código del método, como se muestra en las siguientes imagenes:


  4. Agregamos las siguientes líneas al inicio del código de la clase MainWindow.cs , para utilizar los miembros de los ensamblados System.Security.Principal y System.Threading respectivamente.


    using System.Security.Principal;
    using System.Threading;

  5. Dentro del método OnBtnEnterClicked del código generado por MonoDevelop para el evento del botón btnEnter, escribimos el siguiente código, el cual contiene toda la funcionalidad de nuestro programa:

    Nuestro programa entonces se vera como en la siguiente imagen:


  6. Ahora creamos el código del evento Clicked para el botón btnClose de la misma forma que lo hicimos para el botón btnEnter, cuya acción será terminar el programa, por lo que escribimos el siguiente código dentro del método generado.


    protected virtual void OnBtnCloseClicked (object sender, System.EventArgs e)
    {
    Application.Quit();
    }


  7. Para compilar el programa hacemos click en el submenú Construir todo debajo del la opción Construir en el menú principal. En caso de ejecutar el programa hacemos click en cualquiera de las opciones Ejecutar o Depurar bajo el menú Ejecutar en el menú principal.



  8. Si el programa se compila correctamente al ejecutarse mostrará el resultado como en la siguiente imagen:


  9. Si ejecutamos el programa desde la terminal como superusuario nos mostrará el resultado como en la siguiente imagen:



Vemos en el resultado de la ejecucción que el metódo de autenticación es POSIX.

domingo, 25 de julio de 2010

Conceptos Básicos de seguridad en .NET (parte II)

Autorización

La autorización ocurre inmediatamente después de la autenticación y es como el sistema determina que recursos pueden utilizarse de acuerdo con la autenticación, regresando a la analogía del edificio la autorización ocurre después que nos identificamos (autenticación) ante el guardia y le decimos a que piso vamos, entonces nos da un gafete con el número de piso y que nos autoriza movernos únicamente en ese piso mientras nos encontremos dentro el edificio.

La interfaz IPrincipal

El modelo de seguridad basado en roles (roled-based security o RBS) permite controlar el acceso de los usuarios a los recursos en base a su identidad y su pertenencia a un grupo o membership, este modelo esta diseñado para ser independiente de la plataforma donde se implemente por lo que .NET utiliza el concepto de principal (representado por la interfaz IPrincipal) como una forma de abstraer este modelo y encapsular la información acerca del contexto de seguridad (security context) de la entidad (usuario o objeto) que ejecuta el código.

Hay diferentes tipos de objetos Principal cada uno para cada tipo de identidad y de membership, .NET proporciona los siguientes tipos de principales.

  • Windows Principal: Si utilizamos la seguridad Integrada de Windows este objeto representa la identidad, la autenticación y los roles de Windows.
  • Generic Principal: Representa una seguridad a nivel aplicación, independiente de la seguridad de Windows, los roles y los usuarios utilizan un método personalizado de autenticación como por ejemplo una tabla en una base de datos.

Hay dos técnicas para crear objetos Principal dependiendo de si una aplicación requiere hacer la validación algunas veces o durante toda su ejecución. Vamos a mostrar estas formas utilizando como ejemplo el objeto WindowsPrincipal.

La primera técnica se recomienda si requerimos hacer la validación de cierto código algunas veces durante la ejecución, la sintaxis es:

WindowsIdentity wi = WindowsIdentity.GetCurrent();
WindowsPrincipal wp = new WindowsPrincipal(wi);

En esas lineas, primero obtenemos una instancia de WindowsIdentity al consultar la cuenta de Windows que ejecuta el código con el método GetCurrent y después la usamos como parámetro para construir un objeto WindowsPrincipal.

La segunda técnica se utiliza si requerimos hacer la validación durante toda la ejecución de la aplicación entonces en este caso debemos establecer la seguridad de Windows a nuestro hilo principal de ejecución ya que .NET de forma predeterminada no estable esa propiedad, entonces la sintaxis es la siguiente:

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal wp = (WindowsPrincipal)Thread.CurrentPrincipal;

En esas líneas primeramente establecemos la política de autorización al dominio de la aplicación con el valor de la enumeración PrincipalPolicy , después obtenemos el Principal del hilo de ejecución y hacemos un casting a un objeto WindowsPrincipal, si no establecemos la política no podremos hacer el casting de Thread.CurrentPrincipal a WindowsPrincipal ya que como mencionamos anteriormente .NET no establece esta propiedad.

Una vez teniendo el objeto WindowsPrincipal además de las propiedades y métodos de la clase WindowsIdentity podemos determinar su pertenencia a un grupo o rol, con el método IsInRole. El método IsInRole de WindowsPrincipal tiene tres sobrecargas la primera recibe como argumento una cadena conteniendo el nombre del grupo o rol que debe escribirse para grupos basados en dominios de la siguiente forma:

[NombreDelDominio]\[Grupo]

O de la siguiente forma si es para grupos de la computadora local.

[NombreDeLaMaquina]\[Grupo]

La segunda sobrecarga recibe un RID (Role Identifier) y la tercera recibe una enumeración WindowsBuiltInRole
La tabla siguiente lista los identificadores del rol con su correspondiente valor en la enumeración WindowsBuiltInRole

+----------------+------+
|AccountOperator |0x224 |
|Administrator   |0x220 |
|BackupOperator  |0x227 |
|Guest           |0x222 |
|PowerUser       |0x223 |
|PrintOperator   |0x226 |
|Replicator      |0x228 |
|SystemOperator  |0x225 |
|User            |0x221 |
+----------------+------+

El siguiente programa demuestra el uso de la primera técnica de validación para conocer la autorización de una entidad. Descarga el código fuente del programa de este enlace.

Al compilar y ejecutar el programa con una cuenta de administrador mostrará el siguiente resultado:

Ahora bien, si ejecutamos el programa con el comando

runas /user:[Usuario] [Programa]

en este caso con la cuenta del usuario postgres,como se muestra en la imagen:

El programa mostrará el siguiente resultado:

Y ahora demostramos la segunda técnica utilizando la política del dominio de la aplicación, algo más elaborado que el ejemplo anterior. Descarga el código fuente de este ejemplo de este enlace. Al compilar las clases y ejecutar el programa con la opción false nos mostrará la excepción de que no hemos establecido una política de autorización.

Si ejecutamos el programa sin argumentos nos mostrará las instrucciones de uso.

Si ejecutamos el programa correctamente,nos mostrará la información como en la siguiente imagen

miércoles, 14 de julio de 2010

Conceptos Básicos de seguridad en .NET (parte I)

La seguridad es un tema que debe estar presente desde el comienzo del diseño de todo sistema de información, más aún si este sistema será utilizado por usuarios desde Internet. Dos conceptos básicos para entender la seguridad de los sistemas es la autenticación y la autorización.

Autenticación

La autenticación es el proceso mediante el cual el sistema identifica y válida que el usuario pruebe quién dice ser, es similar a cuando hacemos una visita a un edificio y un guardia de seguridad en la entrada nos solicita una credencial para que nos identifiquemos, el mecanismo de credenciales más usadas en los sistemas de información es el login y el password. Entonces en definición la autenticación es el mecanismo que se refiere a probar y validar quiénes somos dentro del sistema, esta identidad consiste generalmente del login de usuario y del rol asociado con ese login, NET proporciona los siguientes mecanismos de autenticación:

Windows Authentication Utiliza la seguridad del sistema operativo windows y compara las credenciales (login y password) con las credenciales de Windows una vez identificado, windows utiliza un número de 96 bits llamado SID (security identifier) para identificarlo.

Passport Authentication En este tipo los usuarios utilizan sus cuentas de Hotmail o de Windows Messenger para autenticarse y por ende su servicio de registro en caso de no tener una cuenta passport, para utilizar esta autenticación es necesario descargar e instalar Passport SDK desde Microsoft Passport Network.

Forms Authentication (ASP.NET) Aquí se realiza mediante un formulario solicitando el login y el password al usuario, cuando ASP.NET válida las credenciales como correctas crea una cookie encriptada que se adjunta a cada respuesta de petición, por eso se dice que esta autenticación es basada en token (token-based), si el runtime de ASP .NET no encuentra la cookie entonces redirige al usuario a la pantalla del login, este tipo de autenticación es la más personalizable y portable que las anteriores.

Estos mecanismos se utilizan en conjunto con la seguridad basada en roles de .NET (role-based security) que se fundamenta en dos conceptos importantes: identidades y principales.
La identidad de un usuario está representada en .NET por los siguientes tipos de identidades que se encuentran representadas en el Framework por clases que implementan la interfaz IIdentity.

Windows identity Se basa en los métodos de autenticación soportados por el sistema operativo Windows, esta identidad tiene la propiedad de hacerse pasar por otro usuario con la característica de impersonation(suplantación) además de ser una forma muy segura de autenticar usuarios.

Generic identity Se basa en un método personalizado de autenticación que se define a nivel aplicación, al ser un método personalizado por lo tanto no depende de las características del sistema de seguridad de Windows.

Passport identity Utiliza la autenticación del modulo de Passport de Microsoft donde los usuarios utilizan las credenciales de Hotmail o Windows Live para acceder a cualquier sistema que implemente el servicio Passport (single sign-inservice).

Si bien se recomienda utilizar los mecanismos proporcionados por el framework, .NET permite también crear mecanismos personalizados de autenticación implementando la interfaz IIdentity.

Descarga el código del programa WindowsIdentitySample ejemplo de este enlace

Al ejecutarse el programa mostrará la siguiente salida en Microsoft Windows:

Y la siguiente salida al ejecutarse en Linux utilizando Mono

Descarga el código del programa GenericIdentitySample utilizando la clase GenericIdentity de este enlace.

Al ejecutarse el programa mostrará la siguiente salida en Microsoft Windows:

domingo, 30 de mayo de 2010

Trabajando LINQ para XML con Monodevelop Parte II de II

Esta es la segunda parte del post anterior Trabajando LINQ para XML con Monodevelop, aunque este tutorial supone que los dos proyectos están dentro la misma solución, los dos proyectos son independientes uno del otro, por lo que pueden crearse en diferentes soluciones.


Consultando XML con LINQ

Ahora agregamos un segundo proyecto a nuestra solución, este proyecto será una aplicación GTK# que llamaremos “SegundoLinqXML” como se muestra en la siguiente imagen y que nos mostrará como consultar el archivo XML con LINQ creado con la aplicación de consola anterior.



Utilizando el diseñador agregamos y acomodamos los siguientes controles GTK# con sus respectivos identificadores al formulario.
Tipo de control:Gtk.Entry NombretxtQuery

Tipo de control:Gtk.Button NombreBtnBuscar

Tipo de control:Gtk.RadioButton NombresRbCodigo,rbIdArticulo,rbNombre

Tipo de control:Gtk.TreeView NombresResultados

Colocando los controles el formulario deberá verse como en la siguiente imagen

El código completo es el siguiente:


El siguiente fragmento de código muestra como realizar la consulta del archivo XML donde la variable col adquiere el valor de cualquier elemento dentro del elemento table y donde el valor contenga el texto escrito dentro de txtQuery, es aquí donde en esencia se utilizan las expresiones de consulta de LINQ una vez que se carga el documento XML en memoria.




Construimos la aplicación pulsando el botón F8, seleccionamos el archivo de proyecto y haciendo click con e botón secundario del ratón seleccionamos la aplicación para que se inicie al ejecutar la solución, al ejecutarla teclear un valor y pulsar el botón consultar observaremos cualquiera de los siguientes resultados dependiendo del control radio seleccionado.



miércoles, 26 de mayo de 2010

Trabajando LINQ para XML con Monodevelop Parte I de II

XML se ha convertido en un excelente estándar abierto para el intercambio de información entre aplicaciones de software debido a la manera de representar información estructurada, independiente de la plataforma, lenguaje de programación o sistema operativo, es utilizado extensamente en archivos y protocolos de Internet por ser un formato fácil de leer y suficientemente flexible para adaptarse a muchos propósitos. Debido a estas características XML y sus tecnologías están completamente integradas y soportadas por la plataforma .NET mediante un conjunto de clases que proporcionan lectura y escritura de documentos, validación, navegación, serialización, transformación y búsquedas. Aunque estas clases son suficientes para trabajar con XML su utilización no es sencilla y puede producir código difícil de mantener, por lo que .NET incorpora LINQ para XML (LINQ to XML) como una mejor manera de trabajar con XML.


Creando el archivo XML

Para mostrar de una manera práctica la utilización de LINQ para XML, ejecutamos MonoDevelop y creamos una nueva solución en el menú “Archivo”, del lado derecho de la ventana de nueva solución seleccionamos el icono que dice “Solución en blanco” y en el cuadro de texto nombre escogemos “LinqXML”, esta será la solución que contenga los dos proyectos de este tutorial.



Agregamos a nuestra solución un proyecto de consola, le llamamos CrearXML , como se muestra en la siguiente imagen.


Para que el soporte de LINQ a XML es importante hacer referencia a los siguientes ensamblados:

System.Linq Es el ensamblado principal y básico que contiene todas las clases e interfaces para trabajar con LINQ.

System.Xml.LinqContiene las clases y extensiones para manipular XML con LINQ.

Esto se logra haciendo click derecho sobre el archivo de proyecto y en el menú desplegable escogemos la opción “Editar referencias” (Edit References) como se muestra en la imagen siguiente.



Ahora completamos el código generado por monodevelop, para que el programa completo quede como en el siguiente listado.




La diferencia de la sintaxis para crear documentos XML con respecto a la sintaxis empleada con las clases del ensamblado System.Xml, es que esta sintaxis se enfoca más en los elementos (representados por la clase XElement) que en el documento (representado en la clase Xdocument ).
En este listado creamos el documento XML de una manera declarativa anidando varias objetos XElement dentro de un objeto Xdocument , al final llamamos al método Save para guardar el XML en el disco.
Construimos la aplicación pulsando la tecla F8 y al ejecutarse veremos el resultado en la ventana de salida de MonoDevelop como se muestra en la imagen siguiente.

miércoles, 19 de mayo de 2010

El patrón singleton con Monodevelop y PostgreSQL

En el post anterior mostré un ejemplo utilizando el patrón Singleton con conexiones a bases de datos SQL Server ejecutándonse bajo Microsoft Windows, ahora mostraré las modificaciones que tuve que realizar a ese ejemplo para que funcione con PostgreSQL como base de datos y Linux como sistema operativo.
Primeramente abrí el proyecto en Monodevelop, después descargue la última versión de la biblioteca Npgsql para tener actualizado los últimos cambios de esta biblioteca, lo cuál es recomendable ya que además de arreglar los errores el equipo responsable agrega nuevas funcionalidades, una vez descargada la biblioteca comence con las siguientes modificaciones: 1-.Quitar la referencia al ensamblado de Sql Server (System.Data.SqlClient) y reemplazarlo por el de PostgreSQL (Npgsql), esto se hace dentro del explorador de la solución, haciendo click derecho sobre las referencias como se muestra en la imagen.

Nos aparecerá la ventana "edit references", ahí escogemos la pestaña que dice "Ensamblado .Net" para buscar en el sistema de archivos en la ruta donde descargamos y descomprimimos la biblioteca Npgsql,esto para seleccionar el ensamblado Npgsql.dll como se muestra en la siguiente imagen.

2-. Reemplazar en el código de las clases DataBase y DataBase2 respectivamente el namespace System.Data.SqlClient por Npgsql using System.Data.SqlClient; por using Npgsql;

3-. También en el código de esas clases reemplazar las líneas donde se hace la declaración del objeto que representa la conexión y donde se realiza la creación de dicho objeto, reemplazar las siguientes líneas:

SqlConnection _conn = null;
_conn = new SqlConnection();
por
NpgsqlConnection _conn = null;
_conn = new NpgsqlConnection();

4-. En estas mismas clases cambiar el tipo de excepción en el catch del try del metódo GetConnection(). catch(SqlException x) por catch(NpgsqlException x)

5-. Reemplazar el evento StateChange del objeto NpgsqlConnection y el delegado asociado al evento, por una propiedad de tipo string que infome de las características de la conexión, esto debido a que aún el proveedor de datos de postgreSQL no cuenta con esta característica.

StateChange += delegate(object o,StateChangeEventArgs args){
    Info = String.Format(" {1}| {2}| {3}|",args.CurrentState.ToString(),System.DateTime.Now.ToLocalTime(),
_conn.DataSource,_conn.Database);
por
Info = String.Format(" {0}|{1}| {2}| {3}|",GetCurrentState,System.DateTime.Now.ToLocalTime(),
_conn.DataSource ,_conn.Database);
Agregando la siguiente propiedad

public string GetCurrentState{ get {return (IsOpen == true ? "Open" : "Closed");}}

Terminando los cambios debemos de configurar MonoDevelop para que al ejecutar la aplicación el programa se ejecute en una terminal propia y no en la ventana de salida (output) de MonoDevelop, esto se hace en el menú principal en la opción "Proyecto" eligiendo el submenú "Opciones", nos mostrará una pantalla como la siguiente imagen.

Después de estos cambios podemos observar el resultado, de forma idéntica al resultado logrado en la plataforma Microsoft.Ingreso de los parámetros de conexión.

Sin el uso del patrón Singleton, cambian los tiempos en la conexión

Usando el patrón Singleton, el tiempo es único.

lunes, 3 de mayo de 2010

El patrón singleton


Muchos problemas de rendimiento (performance) y de escalabilidad (scalability) ocurren si no manejamos correctamente las conexiones a las bases de datos, hay que tener en presente que las conexiones para acceder a una base de datos son un recurso que consume memoria y tiempo de procesador, por lo que solo se deben crear las conexiones necesarias para el funcionamiento de las aplicaciones y estas deben cerrarse tan pronto hayan sido ocupadas.
Una buena práctica es que todas las clases que acceden a los recursos de la base de datos utilicen siempre una única conexión sin importar el número de instancias que estas clases generen al ser ejecutadas dentro de una aplicación, una solución recomendada a este escenario es utilizar los patrones de diseño de software.


Conectarse a una base de datos con el patrón Singleton


Es un patrón de diseño del tipo creacional que nos asegura la creación de únicamente la instancia de un objeto sin importar el número de veces que se intenten crear más instancias de ese objeto.
citando el clásico libro de the gang of four Design Patterns:Elements of Reusable Object-Oriented Software, 1995, Pearson Addison Wesley "The Singleton design pattern must ensure a class only has one instance, and provide a global point of access to it"

Este patrón se utiliza para representar un objeto de hardware (por ejemplo una impresora), un componente del sistema operativo (un archivo o un directorio) o bien un recurso externo limitado (como una conexión a una base de datos), esta instancia revisará si ya ha sido creada, atenderá las peticiones de los objetos que la utilicen como un punto global de acceso (similar a una variable global) y sera responsable del mantener el seguimiento de su estado.
El esqueleto clásico de un Singleton es el siguiente:

A continuación voy a mostrar el ejemplo de una clase que representa una conexión a una base de datos sin utilizar el patrón Singleton, para mostrar como se crea una conexión por cada ocasión que nosotros llamamos a la clase lo cual repercute en la escalabilidad y el desempeño de la aplicación si se tuvieran que invocar decenas o cientos las ejecuciones a esta clase. Descarga el código del ejemplo sin utilizar Singleton de este

Al compilar y ejecutar la aplicación se mostrará el siguiente menú.

Escogiendo la opción (a) nos mostrará el menú para solicitarnos los parámetros de la cadena de conexión, si repetimos este procedimiento nos mostrará
las conexiones hechas hacia el servidor, una por cada vez que hayamos completado la opción (a) como se muestra en la siguiente imagen.



Observamos en la imagen como es diferente el tiempo entre cada una de las conexiones ya que se crea una conexión por cada llamado.



Bien ahora mostraremos el mismo ejercicio utilizando el patrón Singleton en el código de la clase DataBase, pero para no sobrescribir la clase DataBase del ejercicio anterior, nombraremos la clase Singleton como DataBase2.

Descarga el código del ejemplo utilizando Singletonde este

Si analizamos el patron Singleton vemos el uso de los modificadores private y static en el constructor hace que no se pueda crear la clase de forma directa, sino solo a traves del método public GetInstance(string conStr) que regresa la instancia creada y por ende sus propiedades y métodos públicos.
Ejecutando la aplicación, seleccionando la opción (a) para conectarse a una base de datos y creando varias conexiones debemos de ver la salida del programa como en la siguiente pantalla:


Observamos en la imagen como el tiempo y las propiedades entre cada una de las conexiones es siempre el mismo, ya que se crea una sola instancia global de acceso.

lunes, 26 de abril de 2010

Uso de funciones PL/SQL en postgreSQL

Una función (function) en PostgreSQL son sentencias SQL agrupadas y precompiladas para ejecutarse en bloque dentro del servidor, a diferencia de las consultas SQL donde cada consulta es procesada en tiempo de ejecución por el servidor , las funciones procedurales son compilados cuando son creados, ya que el servidor asume que serán ejecutados más de una vez, un función ofrece las siguientes ventajas:

  • No sobrecarga la comunicación cliente/servidor al evitar enviar una consulta tras otra, en su lugar procesa una consulta tras otra y envía únicamente el resultado.
  • Cuando y se ejecuta la primera vez se crea un plan preparado de ejecución, las siguientes ejecuciones reutilizan el plan preparado.
  • Agrega estructuras de control y capacidad de calculo al lenguaje SQL.
  • Las mismas consultas están disponibles para varias aplicaciones.
  • Seguridad los datos solo están accesibles mediante las funciones y evita el uso de SQL injection.

De los lenguajes más utilizados para crear funciones en postgreSQL, se encuentra PL/pgSQL, el cual se distribuye como un módulo cargable junto con postgreSQL, para emplearlo en nuestra base de datos es necesario darlo de alta, de la siguiente manera.

Fig 1 Agregando el soporte PL/SQL

Revisamos si ya lo tenemos disponible en nuestra base de datos para utilizarlo La sintaxis de PL/pgSQL (similar al lenguaje PL/SQL de Oracle)

Fig 2 Comprobando la instalación del lenguaje PL/SQL

Utilizando PL/pgSQL con C#

En este ejemplo usaremos PL/pgSQL y C# para resolver un requerimiento practico como seria relacionar la columna city de nuestra tabla authors en nuestra base de datos con una tabla llamada cities donde se encontrará la información de la columna ciudad mas un identificador.

Fig 3 La tabla autores

La relación deberá de quedar de la siguiente manera, donde la columna city se debe cambiar por la clave primaria de la tabla cities que tendrá como clave primaria la clave de la ciudad y una columna adicional llamada city que contendrá el nombre de la ciudad.

Ahora usamos la siguiente función AddCities(varchar) para tomar los valores de la columna city en la tabla authors, crear un identificador único para la llave primaria, insertar ese valor de clave primaria junto con el nombre de la ciudad y por último sustituir los valores en la columna city y reemplazarlos con el valor de la llave primaria en la tabla cities.

Descargamos el código fuente del ejemplo del siguiente

Lo compilamos y lo ejecutamos

    mcs /t:winexe -r:System.Data,Npgsql -pkg:gtk-sharp-2.0 ExecutePgFunction.cs
Fig 5 Compilación del programa

Podemos probar nuestro programa invocando la funcion version() predeterminada de PostgreSQL.

Fig 6 Ejecutando la función version() de PostgreSQL

Al ejecutar la función sin argumentos desde el formulario se vera el mismo resultado.

Fig 7 El programa ejecutando función version().

Aquí el driver de PostgreSQL para .NET ejecuta la función usando la clase NpgsqlCommand la cual recibe como argumento el nombre de la función y la conexión al servidor donde se encuentra.

    NpgsqlCommand cmd = new NpgsqlCommand(“version”, conn);

Si la función recibe parámetros, debemos de crear una instancia de la clase NpgsqlParameter() por cada uno de los parametros que reciba, es muy importante no olvidar indicarle a la clase NpgsqlCommand que el comando que ejecutaremos es un stored procedure o una función pl/sql, esto lo hacemos mediante la instrucción:

    cmd.CommandType = System.Data.CommandType.StoredProcedure;

Para mayor referencia no olvidar leer la documentación del data provider para PostgreSQL. Si todo es ejecutado correctamente, ya podemos probar la función AddCities con el argumento del nombre de la ciudad y debe devolvernos la clave primaria de la tabla cities.

Fig 8 El programa ejecutando la función AddCities