viernes, 28 de abril de 2017

Utilizando la clase NpgsqlError de la enumeración NpgsqlException.Errors

Una forma precisa de diagnosticar los errores PostgreSQL en una aplicación :NET es mediante el uso de la clase NpgsqlError de la cual se pueden obtener detalles adicionales a la excepción generada esta clase esta incluida en la enumeración Errors la cual al recorrerse y consultar las propiedades de la clase NpgsqlError podemos obtener información específica acerca de los errores y advertencias que se generan al ejecutar los comandos SQL o Store procedures en PostgreSQL por medio de una aplicación .NET que haga uso del driver Npgsql.

A continuación mostramos una aplicación de consola que se conecta a una base de datos PostgreSQL, ejecuta un comando SQL para crear un nuevo registro en una tabla y envia la excepción generada hacia un archivo de texto.


Aquí el código para crear la tabla Books


Aqui el código de la clase Book



Aquí el código de la clase BooksManager


using System;
using System.Data;
using Npgsql;
using NpgsqlTypes;
using TestNpgsqlError;

namespace TestNpgsqlError
{
    public class BooksManager
    {

        public static int Insert(Book b)
        {
            var resp = 0;
            var commandText = @"INSERT INTO Books(title,numpages,pubyear,created)
VALUES(:title, :numpages, :pubyear, :created)";
            try
            {
                string connStr = @"Server=127.0.0.1;Port=5432;Database=testBook;
         User ID=postgres;Password=Pa$$W0rd";
                using (NpgsqlConnection conn = new NpgsqlConnection(connStr))
                {
                    conn.Open();
                    using (NpgsqlCommand cmd = new NpgsqlCommand(commandText, conn))
                    {
                        cmd.CommandType = CommandType.Text;
                        cmd.Parameters.Add("title", NpgsqlDbType.Varchar).Value = b.Title;
                        cmd.Parameters.Add("numpages", NpgsqlDbType.Numeric).Value = b.NumPages;
                        cmd.Parameters.Add("pubyear", NpgsqlDbType.Numeric).Value = b.PubYear;
                        cmd.Parameters.Add("created", NpgsqlDbType.Timestamp).Value = DateTime.UtcNow;
                        resp = cmd.ExecuteNonQuery();
                    }
                }
                return resp;
            }
            catch (NpgsqlException ex)
            {
                LogErrors(ex);
                throw new ApplicationException(@"A DataBase error has occurred, 
please see the log file.");
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message);
                throw new Exception("A exception has occured, please see the log file.");
            }
        }

        static void LogErrors(NpgsqlException ex)
        {
            string msg = null;
            foreach (NpgsqlError item in ex.Errors)
            {
                msg = String.Format("Code: {0}\n", item.Code);
                msg += String.Format("Detail: {0}\n", item.Detail);
                msg += String.Format("Error: {0}\n", item.ErrorSql);
                msg += String.Format("File: {0}\n", item.File);
                msg += String.Format("Hint: {0}\n", item.Hint);
                msg += String.Format("Line: {0}\n", item.Line);
                msg += String.Format("Message: {0}\n", item.Message);
                msg += String.Format("Position: {0}\n", item.Position);
                msg += String.Format("Routine: {0}\n", item.Routine);
                msg += String.Format("Severity: {0}\n", item.Severity);
                msg += String.Format("Where: {0}\n", item.Where);
                msg += String.Format("======{0}======\n", DateTime.Now.ToString());
            }
            Logger.Error(msg);
        }
    }
}

Aquí el código de la clase Logger


Finalmente, el código la clase principal MainClass.


En la clase BooksManager se encuentra el método estático LogErrors en donde se realiza toda la funcionalidad, aquí es donde se itera por la enumeración Errors de la clase NpgsqlException y se escribe la información en el archivo de texto.


Antes de compilar y ejecutar la aplicación vamos a ocasionar un error en la sentencia de la consulta SQL. Por ejemplo no escribir correctamente el nombre de la tabla.



var commandText = "INSERT INTO Booksssss(title,numpages,pubyear,created)
VALUES(:title, :numpages, :pubyear, :created)";

Al compilar y ejecutar la aplicación veremos la excepción generada a propósito para poder consultar el archivo log y ver más detalles acerca de la excepción generada.
Compilamos la aplicación con los siguientes comandos:

$ dmcs -t:library -r:System.Data,Npgsql Book.cs BooksManager.cs Logger.cs 
/out:TestNpgsqlError.dll

$ dmcs -r:TestNpgsqlError.dll Main.cs

Ejecutamos la aplicación, como se muestra en la siguiente imagen:



Otra prueba es si escribimos erróneamente los parámetros de la cadena de conexión, por ejemplo cambiar el usuario de la base de datos o no teclear correctamente el nombre de la base de datos.



string connStr = "Server=127.0.0.1;Port=5432;Database=testBooks;User ID=postgressss;
Password=Pa$$W0rd";

Podemos consultar la bitácora y ver como por cada excepción se genera un código y los detalles de la excepción.


Descargar el código fuente del ejemplo (Download the source code)