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:



  Descarga el código fuente

jueves, 25 de noviembre de 2010

Notas de la certificación CCNA de Cisco

Notas de las primeras clases del módulo Aspectos básicos de Networking de CCNA Exploration 4.0.



La problemática básica de toda red está dividida en 3 aspectos:

  1. La interconexión

  2. La colisión de paquetes

  3. El ancho de banda



Debido a la distancia en la conexión física la señal se debilita por lo que es necesario poner un dispositivo en la capa física que ayude a propagar la señal, este dispositivo en capa física se conoce como Hub.
El hub resuelve el problema de la interconexión en cuanto a la propagación de la señal, pero no logra evitar las colisiones debido a que también propaga el residuo de la trama y las colisiones se producen cuando chocan dos tramas. El hub solo reproduce bit a bit y no es capaz de ver la longitud de trama que son 64 bits por lo que no distingue cuando es una trama completa y cuando un residuo de trama.
El tamaño del dominio de colisión es el número de computadoras conectadas a un medio físico y es todo aquel dispositivo que puede verse afectado por una colisión.
A nivel de capa 1 el segmento de red es el cable físico y el dispositivo para segmentar es el hub, si se extiende el cable se extiende también la colisión.



El switch es un dispositivo de capa 2 y hace lo mismo que el hub pero tiene una tabla de conmutación y además es capaz de revisar la longitud de la trama de 64 bits y si es menor a 64 bits elimina la trama por lo que elimina el dominio de colisión.
Todo dispositivo que des encapsule de capa 1 a capa 2 detiene el dominio de colisión y todo dispositivo de capa 2 que des encapsule a capa tres detiene el dominio de broadcast.
La diferencia entre un brigde y un switch es que hacen lo mismo pero el switch lo hace en base a hardware y el brigde lo hace en base a software.
La segmentación en capa 2(a nivel de switches) incluye los dispositivos de capa 1(a nivel de hubs), esta segmentación hace más pequeño el dominio de colisión.
Lo único que no puede detener el switch es el dominio de broadcast, un dominio de broadcast es hasta a donde puede llegar el broadcast.



El dominio de broadcast solo se puede detener en capa tres y a ese nivel trabajan los routers que tienen capacidades para detener el dominio de broadcast y las capacidades de los dispositivos en capas inferiores.
Es decir un router detiene las colisiones y destruye los paquetes de broadcast, además puede diferenciar si es una red WAN o una red LAN.
La segmentación en capa 3 incluye dispositivos de capa 2 (switches) y de capa 1 (hubs) y esta segmentación hace más pequeño el dominio de broadcast.
El switch trabaja con dirección MAC y el router con dirección IP, para sacar el ancho de banda de cada PC la formula es el ancho de banda del medio por el tamaño del dominio de colisión.

Ancho de banda = capacidad del medio (mbps)/tdc

Cada puerto del switch o cada interface del switch es un dominio de colisión.
En resumen:

  • El hub manipula bits

  • El switch manipula tramas

  • El router manipula paquetes

  • La dirección MAC son de 48 bits que representan en Hexadecimal.

  • La dirección MAC nos proporciona identificación.


jueves, 18 de noviembre de 2010

Lecturas de ingeniería de software

El día 19 de noviembre de 2010 dentro del grupo de procesos y estándares para el desarrollo de software se tendrá una lectura acerca de cada una de las posturas de cada autor o empresa que están publicadas en este sitio http://www.semat.org dedicado a la ingeniería de software.


Las posturas se encuentran en el enlace de http://www.semat.org/bin/view/Main/WorkshopPositions


En mí caso me toca leer las posturas de las empresas Ericsson y Fujitsu.


En ese sitio también hacen mención de la muerte de Watts Humphrey un personaje importante en la ingeniería de software, sin duda una lamentable perdida.

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


  Descarga el código fuente

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.


  Descarga el código fuente

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:


  Descarga el código fuente

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


  Descarga el código fuente para PostgreSQL

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:


En caso de un parámetro incorrecto nos mostrará los mensajes de la excepción recibida.


  Descarga el código fuente del proyecto para MonoDevelop