Mostrando entradas con la etiqueta Windows. Mostrar todas las entradas
Mostrando entradas con la etiqueta Windows. Mostrar todas las entradas

martes, 1 de julio de 2014

Obteniendo output parameters de procedimientos PLSQL en PostgreSQL con .NET

En .NET existen dos maneras sencillas de ejecutar una procedimiento PLpgSQL y obtener la información como resultado de su ejecución.

La primera de ellas consiste en utilizar parámetros de salida (output parameters) como argumentos del procedimiento.

Para mostrarles esta manera, en el siguiente código declaro cuatro argumentos para el procedimiento, dos de ellos como parámetros de entrada y dos de ellos como parámetros de salida.

Similar a las funciones o los métodos en otros lenguajes de programación, los procedimientos PlpgSQL son subprogramas que pueden recibir parámetros de entrada (input), salida (output) y ejecutar otros procedimientos, ademas de contar con expresiones para el control del flujo.

Los procedimientos aceptan input parameters (parámetros de entrada), que se utilizan dentro del store procedure como variables locales. También puedes especificar output parameters (parámetros de salida) que permiten que un procedimiento regrese uno o más valores escalares a la rutina que llamo ese procedimiento. Cuando se ejecuta el procedimiento los valores de los parámetros de salida son almacenados en memoria.

Para demostrar su funcionalidad, creo una tabla llamada Products con el siguiente script.

Inserto unos registros de prueba y los ordeno por la columna id de forma descendente de manera que pueda saber cual es el máximo id que me regresá el procedimiento.

Ahora ejecuto el procedimiento, poniéndole valores a sus parámetros. Al terminar su ejecución el procedimiento devolverá el máximo id y la fecha en la que se inserto el registro, estos valores corresponden a sus dos parámetros output.

SELECT usp_insertproduct('M01-04-943419', 'Mesh 3in x 6in');

El código en C# para ejecutar este procedimiento y obtener sus output parameters, quedaría algo así.

La clase principal para ejecutar este código es la siguiente:

Al ejecutar este programa tecleamos el código y el nombre del producto.

Al terminar su ejecución, nos mostrará los valores de los parámetros de salida.

En el arreglo de parámetros definimos los de entrada y de salida. De manera predeterminada todos los parámetros son de entrada excepto los que explícitamente se asignan como salida:

            parameters[2] = new NpgsqlParameter("p_id", p_id);
            parameters[3] = new NpgsqlParameter("p_created",p_created);
            parameters[2].Direction = ParameterDirection.Output;
            parameters[3].Direction = ParameterDirection.Output;

Agregamos los parámetros y ejecutarmos el procedimiento

            cmd.Parameters.AddRange(parameters);
            cmd.ExecuteNonQuery();

Después asignamos los parámetros a variables en C#, para su manipulación en el programa.

       p_id = Convert.ToInt32(cmd.Parameters["p_id"].Value);
       p_created = Convert.ToDateTime(cmd.Parameters["p_created"].Value);

Los output parameters son considerados la mejor opción para regresar valores escalares.

lunes, 19 de mayo de 2014

Deshabilitar el modo autocommit de transacciones en SQL Server

Hay 3 modos básicos de transacciones con los cuales trabaja SQL Server. Estos modos son:

  1. AutoCommit: Cada comando SQL/T-SQL tiene su propio espacio de transacción y automáticamente se hace la confirmación (COMMIT) cuando el comando termina.
  2. Explicit: En este modo se indica el inicio y el final de una transacción de manera programática. Utilizando los comandos: BEGIN TRAN , COMMIT TRAN y ROLLBACK TRAN. Este modo es comúnmente utilizado en store procedures o scripts.
  3. Implicit: En este modo, cuando emites ciertos comandos SQL Server automáticamente empieza una transacción. Entonces debes de confirmar o deshacer la transacción explícitamente utilizando los comandos COMMIT/ROLLBACK.

Autocommit es el modo predeterminado en SQL Server para las transacciones. Aunque este modo puede ser cómodo para el programador ya que no se tienen que escribir los comandos implicitos para abrir y cerrar una transacción, esto resulta peligro en ciertas ocasiones sobre todo si los datos con los que estamos trabajando se encuentran en un ambiente productivo.

Una manera de disminuir ese riego es deshabilitar el modo autocommit.

Esto se logra habilitando el modo de transacciones implícitas con el comando:

SET IMPLICIT TRANSACTIONS ON

Mostraré un ejemplo, habilitaré el modo de transacciones implícitas en SQL Server 2012 y agregaré un registro nuevo a la tabla HumanResources.Department de la base de datos AdventureWorks2012.
Ejecuto los siguientes comandos para agregar un registro.

SET IMPLICIT TRANSACTIONS ON
go
Insert into HumanResources.Deparment(Name,GroupName,ModifiedDate)
values('Software Developer','Research and Development',getdate())
go

Consulto la tabla para ver que se agregó el registro a la tabla.

SELECT * FROM HumanResources.Department ORDER BY DepartmentID DESC

Hasta este punto, si ejecuto ROLLBACK puedo deshacer la modificación a la tabla, si vuelvo a consultar la tabla los datos son los mismos que estaban almacenados antes del INSERT.

ROLLBACK

Vuelvo a ejecutar el INSERT si ahora deseo que la modificación sea permanente, tengo que ejecutar un COMMIT.

Vuelvo a consultar los datos de la tabla y comprobamos que el registro se guardo de forma permanente.

En este modo, si hay comandos que no han sido confirmados (COMMIT) o rechazados (ROLLBACK), SQL Management nos avisa al momento de cerrar la aplicación.

miércoles, 7 de mayo de 2014

Utilizando Message Queue con C# en .NET Parte II

Continuando con el tema de Microsoft Message Queue, mostraré como recibir un mensaje almacenado en la cola de espera. En la primera parte de este tutorial enviamos un mensaje a una cola de espera por lo que ahora hare un programa que utilice el método Receive() de la clase MessageQueueHelper que puse de ejemplo en la primera parte de este tutorial para obtener ese mensaje y mostrarlo.

Hay que recordar que MSMQ trabaja con un principio FIFO (First In, First Out) lo que significa que el primer mensaje en la cola es el mensaje que recuperarás utilizando los métodos Receive() o Peek() de la clase MessageQueue.

Aquí el código fuente del programa:

Al ejecutar el programa se verá la siguiente salida:

Ahora voy a explicar cómo funcionan los métodos de la clase MessageQueueHelper. El método CreateQueue() recibe tres parámetros que indican las siguientes propiedades:

  1. Path: Indica la ubicación de la cola de espera.
  2. Transactional: Especifica si la cola puede aceptar transacciones de mensajes.
  3. Label: El título que describe de la cola de espera.
Para el valor del Path, el “.” Indica que estamos creando la cola de espera en la maquina local y utilizamos el prefijo Private$ para indicar que es una cola de espera privada, si omites este prefijo indica que la cola de mensajes es pública.

 queue = MessageQueue.Create(queuePath,isTransactional);
 queue.Label = label;

En el método SendMessage() utilizamos le asignamos la clase XmlMessageFormatter para dar un tipo de formato al mensaje. Los MessageFormatters implementan la interfaz IMessageFormatter, la cual puede ser aplicada a un mensaje o a toda la cola de espera. Es indispensable que utilices el mismo MessageFormatter tanto para enviar o para recibir el mensaje. Aquí una lista de los Formatters:

  1. ActiveXMessageFormatter: Se utiliza para trabajar con componentes COM.
  2. BinaryMessageFormatter: Utilizado para serializar o deserializar un mensaje en un formato binario.
  3. XMLMessageFormatter: El formatter predeterminado, serializa y deserializa en formato XML.
Aquí está el código donde se utiliza:

 queue = new MessageQueue(queuePath);
 queue.Formatter = new XmlMessageFormatter();

Por último en el método GetMessage() igual que para enviar el mensaje utilizo una clase MessageFormatter para deserializar el mensaje, también utilizo el método Receive() de la clase MessageQueue para obtener el primer mensaje de la cola de forma síncrona, como argumento recibe un TimeSpan que representa el intervalo de tiempo de espera para recibir el mensaje, este argumento es importante o de lo contario si no se recibe el programa se bloqueara hasta que no haya recibido el mensaje.

 queue = new MessageQueue(queuePath);
 queue.Formatter = new XmlMessageFormatter(new Type[]{
 Type.GetType("System.String")
 });
 queueMessage = queue.Receive(new TimeSpan(0,0,2));
 message = queueMessage.Body.ToString();

lunes, 5 de mayo de 2014

Utilizando Message Queue con C# en .NET

Microsoft Message Queue (MSMQ) es un servicio de Windows que permite la comunicación interproceso entre diferentes computadoras de forma asíncrona, entender cómo funciona puede resultar útil en cualquier momento que los clientes y los servidores no tengan una conexión disponible, ya que los mensajes entre ellos son encolados para su transmisión hasta que ambos estén conectados.

El funcionamiento básico de MSMQ es parecido al de una mensajería entre aplicaciones de software, una aplicación prepara un mensaje y lo escribe hacia una línea de espera o cola de mensajes MSMQ. En este contexto una cola de mensajes es un área de almacenamiento temporal que guarda los mensajes hasta que sean transmitidos. El administrador de colas actúa como un intermediario que transmite el mensaje desde su aplicación origen hasta su destino. El propósito de la cola de mensajes MSMQ es el enrutamiento y garantizar la entrega del mensaje, en caso de que el destinatario del mensaje no esté disponible la cola de mensajes mantendrá el mensaje hasta que pueda ser entregado con éxito.

Este mecanismo de transporte proporciona los siguientes beneficios:

  1. Robustez: Los mensajes son almacenados en la línea de espera hasta que son procesados. Si se cae la conexión entre un cliente y un server los mensajes se guardan hasta que una conexión este presente.
  2. Mensajería basada en prioridad:Los mensajes más importantes son los primeros en ser recibidos, después los mensajes que le siguen y así sucesivamente, hasta que los últimos son los de prioridad más baja.
  3. Garantía de entrega:Cuando se llaman los mensajes a través de la red, MSMQ utiliza una transacción para entregar los mensajes, si se lee un mensaje de la línea de espera y ocurre un error se hace un rollback y el mensaje regresa a la línea de espera.
  4. Seguridad: La tecnología de MSMQ utiliza la seguridad de Windows para proporcionar el control de acceso, la auditoría, encriptación y autenticación de mensajes, de hecho el ensamblado System.Messaging es un wrapper para una API nativa.

Hay tres tipos de líneas de espera en MSMQ:

  1. Públicas: están registradas en el Active Directory y permiten a todas las maquinas enviar y recibir mensajes a través de la red.
  2. Privadas: solo se crean en la máquina local y pueden ser únicamente accedidas desde otra máquina si se conocen los nombres exactos de la máquina y de la línea de espera.
  3. Sistema: son principalmente utilizadas para propósitos administrativos o para aplicaciones que necesitan una línea de espera que guarde copias de los mensajes que son procesados, por ejemplo las aplicaciones de auditoría.

Como ejemplo de la utilización de MS Message Queue con C#, hice el siguiente programa que consta de dos clases: MessageQueueHelper y TestMessageQueue, la primera clase tiene los métodos para crear la cola (CreateQueue), enviar mensaje (SendMessage) y recibir mensaje (GetMessage), la segunda clase es un programa que muestra el uso de los métodos (CreateQueue) y (SendMessage).

Aquí el código de la clase MessageQueueHelper

using System;
using System.Messaging;

namespace Samples{
 public class MessageQueueHelper{
static MessageQueue queue = null;
public static Guid CreateQueue(string queuePath,
  bool isTransactional,
  string label)
{
 if(MessageQueue.Exists(queuePath))
  queue = new MessageQueue(queuePath);
 else
 {
  queue = MessageQueue.Create(queuePath,isTransactional);
  queue.Label = label;
 }
 return queue.Id;

}

public static void SendMessage(string queuePath,
  string message,string subject)
{
 message += "\nCreated on " + DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss");
 MessageQueueTransaction trans = null;
 if(MessageQueue.Exists(queuePath))
 {
  queue = new MessageQueue(queuePath);
  queue.Formatter = new XmlMessageFormatter();
  if(queue.Transactional)
  {
  trans = new MessageQueueTransaction();
  trans.Begin();
  }
  queue.Send(message,subject);

  if(queue.Transactional)
   trans.Commit();
  Console.WriteLine("Message sent.");
 }else
  Console.WriteLine("The queue doesn't exist");
}

public static string GetMessage(string queuePath)
{
 string message = null;
 Message queueMessage = null;
 if(MessageQueue.Exists(queuePath))
 {
  queue = new MessageQueue(queuePath);
  queue.Formatter = new XmlMessageFormatter(new Type[]{
    Type.GetType("System.String")
    });
  queueMessage = queue.Receive(new TimeSpan(0,0,2));
  message = queueMessage.Body.ToString();
 }
 else
  message = "That queue doesn't exist";
 return message;
}

 }
}

Bien ahora el código de la clase TestMessageQueue que prueba los métodos de la clase anterior.

using System;

namespace Samples{
public class TestMessageQueue{
public static void Main(string[] args){
bool isTransactional = false;
Console.WriteLine("\nTest MSMQ\n");
try
{
 Console.Write("\nEnter path > ");
 string path = Console.ReadLine();
 Console.Write("\nIs transactional? (1=true/0=false) > ");
 string sTransactional = Console.ReadLine();
 if(sTransactional.Equals("1"))
  isTransactional = true;
 Console.Write("\nEnter a label > ");
 string label = Console.ReadLine();
 Guid guid = MessageQueueHelper.CreateQueue(path,isTransactional,label);
 Console.WriteLine("\nMessageQueue created with guid {0}\n",guid);
 Console.Write("\nMessage subject > ");
 string subject = Console.ReadLine();
 Console.Write("\nMessage to send > ");
 string message = Console.ReadLine();
 Console.WriteLine();
 MessageQueueHelper.SendMessage(path,message,subject);
}
catch(Exception ex){
 Console.WriteLine(ex.Message);
}
}

}
}

Al ejecutar el programa solicitará los siguientes parámetros:

  • Path: Es el nombre de la cola de espera.
  • Is transactional: 1 si la cola es transaccional, 0 si no lo es.
  • Label: Identificador de la cola.

Al crearse la cola de mensajes el programa regresará el identificador: 00000000−0000−0000−0000−000000000000 por tratarse de una cola de mensajes privadas (private MSMQ).

Ahora el programa solicitará el título y el cuerpo del mensaje, después lo enviará hacia la cola de mensajes creada.

Para ver la cola de mensajes creada con el programa y el mensaje enviado, ejecutamos Computer Management de Windows que se encuentra en la ruta Control Panel\System and Security\Administrative Tools y debajo del nodo de Services and Applications veremos el nodo Private Queues debajo del nodo Message Queuing donde se encuentra la línea de espera creada con el programa de ejemplo.

Debajo de la cola de espera myfirstqueue, se encuentra la carpeta Queue messages en donde se puede ver la etiqueta del mensaje.

Si hacemos doble click en el mensaje aparecerá una ventana con cuatro pestañas en donde podemos ver las propiedades del mensaje, en la pestaña body podemos ver el contenido del mensaje.

domingo, 22 de septiembre de 2013

Regular Expressions (expresiones regulares) en PostgreSQL

Cuando las búsquedas con el operador Like no son lo suficientemente flexibles para localizar los registros que necesitamos, PostgreSQL permite las búsquedas de registos mediante el uso de regular expressions (expresiones regulares).

En este par de posts: Regular Expressions en PL/SQL Oracle, parte I y parte II coloque unos ejemplos de la utilización de expresiones regulares en Oracle.

Ahora utilizaré los mismos ejercicios de esas entradas, pero ahora para mostrar las regular expressions en PostgreSQL.

Creamos una tabla llamada membership:

Ahora insertamos algunos registros:

El operador ~

Como primer ejemplo utilizamos el operador ~ (LIKE versión regular expression) en la consulta para buscar en la columna MEMBERSHIP_LASTNAME aquellos registros que empiecen con la letra D.

Aquí un segundo ejemplo en donde buscamos en la columna MEMBERSHIP_LASTNAME aquellos registros que comiencen con las letras de la A a la F.

El operador inverso !

Ahora mostraré los ejemplos anteriores utilizando el operador inverso ! o la negación del operador ~ para el primer ejemplo, esta consulta busca en la columna MEMBERSHIP_LASTNAME aquellos registros que no empiecen con la letra D.

El mismo operador de negación para el segundo ejemplo, esta consulta busca en la columna MEMBERSHIP_LASTNAME aquellos registros que no empiecen con las letras de la A a la F.

El operador case-insensitive *

Tanto ~ como ! son case-sensitive, si necesitas que ambos operadores sean case-insensitive se combinan con el operador * , como en el ejemplo siguiente donde buscamos en la columna MEMBERSHIP_LASTNAME aquellos registros que después del primer caracter tenga la letra O mayúscula repetida una o más veces.

Esta búsqueda no dio resultados porque excepto la primera letra de los registros en la columna MEMBERSHIP_LASTNAME el resto se encuentran en letras minúsculas, entonces para que la consulta encuentre resultados utilizamos el operador *.

Ahora si la consulta anterior mostro los resultados.

viernes, 20 de septiembre de 2013

Regular Expressions en PL/SQL Oracle, parte II

En este post anterior mostré ejemplos de búsqueda con las funciones regexp_like y regexp_instr.

A continuación mostrare ejemplos de las funciones regexp_substr y regexp_replace respectivamente.

Como primer ejemplo de la función regexp_substr, obtendré dos subcadenas (substring), una de la columna MEMBERSHIP_NAME donde el carácter a se repita dos veces en cada registro y otra de la columna MEMBERSHIP_DUE en donde la cantidad comience con un dígito del 1 al 6 y después uno o más dígitos que se repitan.

Como segundo ejemplo de la función regexp_substr obtendré un substring de la columna MEMBERSHIP_DATE cuyos registros terminen con los dígitos del 1 al 6 repetidos una o dos veces.

Como primer ejemplo de la función regexp_replace buscaré dentro de la concatenación de las columnas MEMBERSHIP_NAME y MEMBERSHIP_LASTNAME los registros que tengan un carácter o repetido a partir de la posición 4 y lo sustituiré por la cadena (**found**).

Como último ejemplo ejecutamos la función regexp_replace en un texto y reemplazamos la palabra ‘fox’ por la palabra ‘SUPER CAT’ a partir de la posición 1.

lunes, 16 de septiembre de 2013

Regular Expressions en PL/SQL Oracle, parte I

Una expresión regular (regular expression) es un conjunto de caracteres (signos) conocido como patrón que al buscarse coincide una o más veces en una cantidad considerable de texto, estos patrones se construyen con una notación de caracteres ordinarios y metacaracteres, los cuales tienen un significado especial dentro de la expresión regular e indican las reglas a las que deben someterse los caracteres ordinarios para su interpretación estos bloques básicos de construcción son similares a una expresión algebraica o a un mini lenguaje de programación.

A continuación algunos de los metacaracteres y su significado:

  • ^ coincide el patrón de búsqueda al inicio de una línea.
  • $ coincide el patrón de búsqueda al final de una línea.
  • . coincide cualquier caracter en cualquier lugar.
  • [] especifica un rango de caracteres
  • ? ubica un caracter opcional.
  • + ubica uno o más caracteres.
  • - ubica cero o más caracteres.
  • {n} ubica un caracter que aparece n veces.
  • {n,} ubica un caracter que aparece n o más veces.
  • {n,m}ubica un caracter que aparece de n a m veces.
  • | disyunción o sea un or lógico entre caracteres.

Las expresiones regulares son ampliamente utilizadas en Linux o en otros lenguajes Open Source, además de plataformas como Java y.NET y en bases de datos como PostgreSQL y Oracle. En Oracle las expresiones regulares son utilizadas cada vez que necesites operaciones de búsqueda demasiado complicadas en donde los comandos SELECT y LIKE no sean suficientes. Oracle tiene las siguientes cuatro funciones para su utilización:

  • REGEXP_LIKE: es la versión de expresiones regulares del comando LIKE. Una función booleana que regresa TRUE,FALSE o NULL si en el texto existe una coincidencia con la expresión regular.
  • REGEXP_INSTR: esta función regresa la posición del caracter en el texto donde se encontró una coincidencia con la expresión regular.
  • REGEXP_SUBSTR: extrae una coincidencia de texto encontrada con la expresión regular.
  • REGEXP_REPLACE: ejecuta una operación de búsqueda y reemplazo si se encuentra una coincidencia en el texto.

Como ejemplo de su uso, creamos la siguiente tabla:

Después insertamos los siguientes registros para comenzar a utilizar las funciones.

Elizabeth  Bishop 36736-36738 976.063 02/08/1911
Charles Dickens 36734-5461 2244.789 07/02/1812
Jack London 5462-37314 898.127 12/01/1876
Joseph Conrad 37315-5463 1193.493 03/12/1857
Gustave Flaubert 37313-37316 1435.384 12/12/1821
John Milton 37317-37296 1348.582 09/12/1608
Samuel Taylor 37292-37318 207.449 21/10/1772
Virginia Wolf 37061-106 2077.947 25/01/1882
Walter  Scott 37319-37320 412.72 15/08/1771
Robert Louis  Stevenson 37945-37946 1033.54 13/11/1850
Joseph Rudyard  Kipling 37947-12556 382.41 30/12/1865
Arthur Conan Doyle 12557-10964 1844.945 22/05/1859
George  Orwell 54722-3236 2139.874 25/01/1903

Como primer ejemplo utilizamos la función REGEXP_LIKE para obtener de la columna MEMBERSHIP_LASTNAME los regitros que comienzan con la letra D.La consulta es:

Ahora utilizamos la función REGEXP_LIKE para obtener de la columna MEMBERSHIP_DUE los regitros que terminan con el número 3.La consulta es:

Por último, utilizamos la función REGEXP_LIKE para obtener de la columna MEMBERSHIP_LASTNAME los regitros que tengan las letras de la A a la F. La consulta es:

Ahora ejemplos con la función REGEXP_INSTR. En el primer ejemplo buscamos los registros que en la columna MEMBERSHIP_NAME tengan de 1 a 2 veces la letra A y cuyo posición de coincidencia del texto sea mayor a 0.

En este segundo ejemplo con REGEXP_INSTR buscamos todos los registros que en la columna MEMBERSHIP_NAME comiencen con la letra J o la letra E.

Un último ejemplo con REGEXP_INSTR buscamos todos los registros que en la columna MEMBERSHIP_DATE terminen en el penúltimo dígito del 0 al 9 y en el último dígito del 1 al 2.

domingo, 25 de agosto de 2013

Obtener el primer día del mes en curso con una función first_day() con PL/SQL en Oracle.

En PL/SQL existe la función LAST_DAY() con la que se obtiene el último día del mes en curso, entonces si tenemos que cumplir un requerimiento en donde necesitamos un campo o una variable con el último día del mes en curso simplemente ejecutamos esta función:

Ahora bien, si el requerimiento a cumplir se trata de obtener el primer día del mes en curso, no existe en PL/SQL Oracle una función predeterminada, por lo que para llegar a ese resultado basta con restarle un mes a la fecha en curso con la función ADD_MONTHS(), le aplicamos la función LAST_DAY() para obtener el último día del mes anterior y sumarle un día.

Aquí otra forma alterna de llegar al mismo resultado.

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.

jueves, 5 de marzo de 2009

Code Access Security CAS, la seguridad en el código para .NET

CAS (Code Access Security), es la forma en que los ensamblados solicitan permisos para acceder a ciertos recursos para su ejecución en el CLR, esto proporciona seguridad a nivel código,como una forma complementaria y adicional a la seguridad del sistema operativo.

Esta seguridad debe estar presente sobre todo si de desarrollan componentes, plugins, add-ons o juegos que serán ejecutados en diferentes ambientes que no conocemos ni controlamos. Señalo que esta seguridad es complementaria y en ningún momento deberá reemplazar la seguridad del sistema operativo. Para explicar voy a usar un ejemplo, un banco nos solicito realizar un aplicación donde el usuario genera unos archivos de estados de cuenta esta aplicación en un diseño inicial esta compuesta por un formulario y un ensamblado que se encarga de generar el estado de cuenta en un archivo XML. Obviamente una aplicación de esta naturaleza, necesitaría una disciplina de análisis y diseño, pero para fines ilustrativos, logramos llegar a la etapa de construcción sin la utilización del CAS.

Como un sencillo ejemplo de la utilización de permisos mediante CAS se puede descargar

La solución de ejemplo se muestra más o menos así:

Fig 1. Solución para desmostrar uso de código seguro en C#.

La operación de la aplicación consiste que cuando el usuario presione el botón de generar, se generaría un archivo XML en una carpeta restringida solamente para la aplicacion si se trata de escribir en otra ubicación que no sea la predeterminada .

Fig 2. La aplicación de ejemplo.
Fig 3. La aplicación generando archivos utilizando la ubicación permitida.

La aplicación se ejecuta sin ningún problema hasta que se trate de generar los archivos en una ubicación que no es la ruta predeterminada indicada por por la aplicacion, hasta aqui el sistema operativo no indica ninguna excepción en las bitácoras de seguridad, pero debido a los permisos del CAS que no permiten que la biblioteca escriba en otra ubicación que no sea la indicada en su clase FileIOPermissionAttribute la aplicación no escribirá ningún archivo y lanzará una excepcion del tipo SecurityException.

Fig 3. Configuramos la aplicación para escribir en otra ubicación que no es la permitida.
Fig 4. Lanza una excepción si se intenta escribir en otra ubicación.

Si revisamos el código de la biblioteca proyecto [EstadosCuenta.biblioteca] observamos que el método esta implementado para generar exclusivamente los archivos bajo una carpeta llamada [Movimientos] en la partición [C:\\] y que la protección del ensamblado no dependerá de las validaciones que implementemos en la capa de presentación sino en el ensamblado mismo, por eso al invocar el método y pasarle cómo parámetro una ruta que no sea la predeterminada, este ensamblado solo escribirá en donde se le haya indicado internamente en el código.

¿Cómo podemos evitar que el código de un ensamblado realice operaciones para las que no fue diseñado?

La respuesta sin duda alguna es uno de los objetivos del CAS. Usando CAS podemos evitar que un usuario o un proceso autenticado utilice los métodos del ensamblado para realizar acciones que no están consideradas en la lógica del programa. Para lograr ese objetivo CAS utiliza permisos encapsulados como objetos que pueden ser usados a nivel de métodos o ensamblados, estos permisos pueden ser de manera declarativa usados atributos dentro del código, en este ejemplo utilizamos un permiso de forma declarativa para el método que genera los estados de cuenta.

Los permisos representan acciones que son revisadas cada vez que el CLR carga el ensamblado para ejecutarse, estos permisos son controlados por el CAS.

  1. UIPermission: Controla la manipulación a la interfaz de usuario y el portapapeles.
  2. ResourcePermissionBase: Controla el acceso a los recursos de Windows.
  3. RegistryPermission: Controla el acceso al Registro de Windows.
  4. ReflectionPermission: Controla el acceso a la funcionalidad de la reflexión proporcionada por el CLR.
  5. IsolatedStoragePermission: Controla el acceso a isolated storage.
  6. FileIOPermission: Controla el acceso de escritura o lectura al disco duro.
  7. FileDialogPermission: Controla el acceso a archivos o carpetas.
  8. EnviromentPermission: Controla el acceso a leer, modificar y crear variables de ambiente.

Como nuestro ensamblado esta protegido por la seguridad del CAS y no depende de la validación que implementen las clases que invoquen sus métodos. Siempre es recomendable habilitar la seguridad del CAS con el siguiente comando.

caspol -s on