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

miércoles, 25 de noviembre de 2009

TxF – NTFS Transaccional

Una capacidad de la que no se habla mucho es de TxF, que apareció junto con Vista: es la capacidad de tener transacciones sobre ficheros NTFS. Esas transacciones pueden afectar a uno o a varios ficheros… y no solo eso: gracias al poder de DTS podemos coordinar una transaccion TxF con otros tipos de transacciones como SQL Server o MSMQ!

Como pasa con muchas de las características avanzadas de windows, sólo se puede usar en .NET a través de p/invoke (si obviamos C++/CLI claro)… vamos a ver un ejemplo!

Primero creamos una clase que contenga todas las definiciones de los métodos Win32 que vamos a usar:

public static class NativeMethods
{
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
[DllImport("kernel32.dll", SetLastError = true)]
public static extern SafeFileHandle CreateFileTransacted(string lpFileName,
uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile, IntPtr hTransaction, IntPtr pusMiniVersion,
IntPtr pExtendedParameter);

[DllImport("ktmw32.dll", SetLastError = true)]
public static extern IntPtr CreateTransaction(IntPtr lpTransactionAttributes, IntPtr uow,
uint createOptions, uint isolationLevel, uint isolationFlags, uint timeout, string description);

[DllImport("ktmw32.dll", SetLastError = true)]
public static extern bool CommitTransaction(IntPtr transaction);

[DllImport("ktmw32.dll", SetLastError = true)]
public static extern bool RollbackTransaction(IntPtr transaction);

[DllImport("Kernel32.dll")]
public static extern bool CloseHandle(IntPtr handle);
}





Vamos a usar los siguientes métodos del api de Win32:




  • CreateFileTransacted: Crea o abre un fichero para ser usado de forma transaccional. Una vez obtenido el handle, el resto de funciones win32 que trabajan con handles funcionan transaccionalmente con el nuevo handle.


  • CreateTransaction: Crea la transaccion


  • CommitTransaction: Hace el commit de la transaccion 


  • RollbackTransaction: Hace el rollback de la transacción


  • CloseHandle: Cierra un handle cualquiera (sea de fichero o no y sea transaccional o no).



Vamos a hacer un programilla que abra dos ficheros en modo transaccional, escriba algo en ellos y luego haga commit y/o rollback de la transacción para ver sus efectos…



Primero creamos la transacción y abrimos dos ficheros (suponemos que los nombres nos los pasarán por línea de comandos):




// 1. Crear la transacción
IntPtr transaction = NativeMethods.CreateTransaction(IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, null);
// 2. Abrir dos ficheros de forma transaccional
SafeFileHandle sfh1 = NativeMethods.CreateFileTransacted(args[0], NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE,
0, IntPtr.Zero, (uint)FileMode.CreateNew, 0, IntPtr.Zero, transaction, IntPtr.Zero, IntPtr.Zero);
SafeFileHandle sfh2 = NativeMethods.CreateFileTransacted(args[1], NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE,
0, IntPtr.Zero, (uint)FileMode.CreateNew, 0, IntPtr.Zero, transaction, IntPtr.Zero, IntPtr.Zero);





Una vez tenemos los handles cualquier función Win32 estándard para escribir o leer en ellos nos serviría… por suerte los file streams de .NET pueden ser creados a partir de un handle de Win32, así que podremos utilizar la clase FileStream.



Ahora ya sólo nos queda hacer un commit o un rollback… Para ello si se produce cualquier error durante la escritura haremos un rollback, y en caso contrario haremos un commit. Finalmente debemos cerrar la transacción y por ello usaremos CloseHandle.



El código es tal y como sigue:




try
{
// Escribimos algo en ambos ficheros
using (FileStream f1 = new FileStream(sfh1, FileAccess.ReadWrite))
using (FileStream f2 = new FileStream(sfh2, FileAccess.ReadWrite))
using (StreamWriter sw1 = new StreamWriter(f1))
using (StreamWriter sw2 = new StreamWriter(f2))
{
sw1.Write("Fichero 1");
if (args.Length > 2 && args[2] == "/e")
throw new IOException("Error cualquiera");
sw2.Write("Fichero 2");
}

// Lanzamos el commit. Si todo ha ido bien llegaremos aquí
NativeMethods.CommitTransaction(transaction);
}
catch (IOException ex)
{
// Algun error: lanzamos el rollback
Console.WriteLine("Error en el acceso a ficheros:" + ex.Message);
NativeMethods.RollbackTransaction(transaction);
}
finally
{
// Cerramos la transacción TxF
NativeMethods.CloseHandle(transaction);
}





Como se puede observar la escritura en los ficheros se hace a través de las clases estándard de .NET. Es solo la apertura del fichero que debe hacerse a través de la API de Win32, así como la creación de la transacción.



Si el tercer parámetro que se le pasa al programa es /e el programa simulará un error.



Si ejecutais el programa TxFDemo.exe f1.txt f2.txt vereis que os aparecen los dos ficheros.



Por otro lado si ejecutais TxFDemo f1.txt f2.txt /e vereis que NO os aparece ninguno de los dos ficheros, ya que se lanza la excepción y con ella se hace un rollback de la transacción NTFS.



Ahora imaginad las posibilidades que este sistema ofrece!



Eso sí recordad que es para Windows Vista o superior…



Link: Un artículo sobre TxF bastante interesante de Jason Olson.



Saludos!



pd: Esto es un crosspost desde mi blog en geeks.ms

lunes, 23 de febrero de 2009

[DllImport] y clases genéricas

Un post rápido para decir sólo dos cosas:

  • DllImport y clases genéricas no se llevan bien. Meter un DllImport en una clase genérica (o derivada de alguna genérica) lanza un TypeLoadException.
  • Más importante que la anterior: No nos habríamos topado con el error de haber seguido las recomendaciones de uso de DllImport. Y ni siquiera podemos alegar desconocimiento de ellas, ya que si hubiesemos usado el análisis estático de código se nos habría avisado.

En resumen, ya se ha dicho varias veces por aquí, pero el análisis estático de código es tu amigo… :)

Saludos!

pd: Para variar… crossposting desde mi blog en geeks.ms… :)

martes, 28 de octubre de 2008

IoC o el poder de ceder el control

Hablando con colegas de profesión, me he dado cuenta de que muchos de ellos no terminan de comprender el patrón IoC o las ventajas que su uso comporta… Así que sin ánimo de sentar cátedra he decidido escribir este post, por si le sirve a alguien…
IoC, que corresponde a las siglas de Inversion Of Control, agrupa a varios patrones que tienen en común que el flujo de ejecución del programa se invierte respecto a los métodos de programación tradicionales (wikipedia dixit). Generalmente el programador especifica las acciones (métodos) que se van llamando, pero en IoC lo que se especifican son las respuestas a determinados eventos o sucesos, dejando en manos de un elemento externo todas las acciones de control necesarias cuando lleguen estos sucesos.

Un claro ejemplo de IoC se encuentra en el modelo de eventos de Windows Forms. Cuando vinculamos una función gestora a un evento (p.ej. el Click de un Button), estamos definiendo la respuesta a un determinado evento y nos despreocupamos cuando se llamará a nuestra función gestora. Es decir, cedemos el control del flujo al framework para que sea él que llame cuando sea necesario a nuestro método.

Una de las principales ventajas de usar patrones IoC es que reducimos el acople entre una clase y las clases de las cuales depende, y eso cuando queremos utilizar por ejemplo tests unitarios es muy importante (no seré yo quien hable ahora de las ventajas de TDD cuando ya lo han hecho xxx). De los distintos patrones IoC me interesa comentar específicamente dos: Service Locator y cómo podemos usarlo en .NET. Para más adelante dejo Dependency Injection, otra forma de IoC que también es extremadamente útil.

Id a la nevera, coged una Voll-Damm o cualquier otra cervecilla y sentaos que este post es un poco largo…

Service Locator

El objetivo de Service Locator es reducir las dependencias que tenga una clase. Imaginemos una clase, que depende de otras dos clases (p.ej. ServicioSeguridad y ServicioLogin). Podríamos tener un código tal como:

class Client

{

static void Main(string[] args)

{

new Client().Run();
}

private void Run()

{

// En este punto necesitamos objetos de las clases ServicioSeguridad y ServicioLogger

ServicioSeguridad ss = new ServicioSeguridad();
ServicioLogger sl = new ServicioLogger();
//...

}

}

En este punto tenemos un fuerte acople entre la clase Client y las clases ServicioSeguridad y ServicioLoggger. Seguiríamos teniendo este mismo acople incluso aunque utilizáramos interfaces porque deberíamos hacer el "new":

IServicioSeguridad ss = new ServicioSeguridad();

IServicioLogger sl = new ServicioLogger();


Las principales desventajas de esta situación son:
  1. Las clases que implementan las dependencias (en nuestro caso ServicioSeguridad y ServicioLogger) deben estar disponibles en tiempo de compilación (no nos basta con tener solo las interfaces).
  2. El fuerte acople de la clase con sus dependencias dificulta de sobremanera su testing. Si queremos utilizar Mocks para de ServicioSeguridad o ServicioLogger vamos a tener dificultades
El patrón de ServiceLocator soluciona estos dos puntos, sustituyendo las dependencias de la clase Client por dependencias a los interfaces y a un elemento externo, que llamaremos Contenedor encargado de devolver las referencias que se le piden.

Cuando la clase necesita un objeto en concreto, lo pide al contenedor:

IServicioSeguridad ss = container.Resolve<IServicioSeguridad>("servicioseguridad");

IServicioLogger sl = container.Resolve<IServicioLogger>("serviciologger");

El método Resolve devolvería una referencia del tipo especificado en el parámetro genérico de acuerdo con un identificador. Evidentemente falta alguien que cree el contenedor y que agregue los servicios a él. Es decir, en algún sitio habrá algo como:

container = new IoCContainer();

container.Add<IServicioSeguridad, ServicioSeguridad>(new
ServicioSeguridad(), "servicioseguridad");

container.Add<IServicioLogger, ServicioLogger>(new
ServicioLogger(), "serviciologger");

La gran diferencia es que esto no tiene porque estar en la clase Client. Simplemente pasándole a la clase Client una referencia al contenedor, eliminamos todas las dependencias de la clase Client con las clases que implementan los servicios. Y donde creamos el contendor? Pues depende… si estamos en nuestra aplicación, lo podemos crear en el método que inicialice la aplicación, pero si queremos probar la clase Client con tests unitarios podemos crear el contenedor en la inicialización del test…. Y lo que es mejor: rellenarlo con Mocks de los servicios!

Así, nuestro programa podría tener una clase Bootstrapper que crea el contenedor de IoC y lo inicializa con los objetos necesarios:

class Bootstrapper

{

static void Main(string[] args)

{

IIoCContainer container = new IoCContainer();
container.Add<IServicioSeguridad, ServicioSeguridad>(new
ServicioSeguridad(), "servicioseguridad");

container.Add<IServicioLogger, ServicioLogger>(new
ServicioLogger(), "serviciologger");
new Client(container).Run();

}

}

Pero si queremos usar tests unitarios de la clase Client, podemos cambiar los objetos por Mocks fácilmente:

[ClassInitialize]

public static
void Init(TestContext context)

{

container = new IoCContainer();

container.Add<IServicioSeguridad, ServicioSeguridadMock>(new
ServicioSeguridadMock(), "servicioseguridad");

container.Add<IServicioLogger, ServicioLoggerMock>(new
ServicioLoggerMock(), "serviciologger");

}

[TestMethod]

public void TestMethod1()

{

Client c = new Client(container);

c.Run(); // Este método Run usará los Mocks!

}


Fijaos que podemos lanzar tests unitarios sobre la clase Client, sin necesidad alguna de cambiar su código y utilizando Mocks. Además, la clase Client no tiene ninguna dependencia con las implementaciones de los servicios que utiliza, así que no es necesario ni que existan para poder crear la clase Client (sólo necesitamos las interfaces).

Unity

Aunque existen varios contenedores IoC open source para .NET, Microsoft tiene el suyo, también open source, llamado Unity (http://www.codeplex.com/unity/). Unity proporciona soporte para los patrones Service Locator y Dependency Injection.
Para que veais un poco su uso he dejado un proyecto de herramienta de línea de comandos para listar los ficheros de un directorio (vamos un dir, jejejee…. :P).

La solución está dividida en varios proyectos:
  1. DemoIoC: Contiene el Bootstrapper, la clase que inicializa el contenedor de Unity, agrega la clase llamada ServicioFicheros y utiliza un objeto Cliente para realizar las acciones de la línea de comandos.
  2. Cliente: Contiene la implementación de la clase Cliente.
  3. Interfaces: Contiene las interfaces del servicio (en este caso sólo una)
  4. Implementations: Contiene las implementaciones del servicio (en este caso sólo una)
  5. Mocks: Contiene las implementaciones de los Mocks (en este caso sólo una)
  6. UnitTests: Contiene tests sobre la clase Cliente, usando un Mock del servicio ServicioFicheros.
El ejecutable (proyecto DemoIoC, assembly DemoIoC.exe) es un archivo de línea de comandos que acepta dos parámetros:
DemoIoC –l para listar todos los ficheros (del directorio actual)
DemoIoC –e:fichero.ext Indica si el fichero "fichero.ext" existe (en el directorio actual).
Si lo ejecutáis veréis que NO funciona bien: lista los ficheros correctamente, pero devuelve que un fichero existe cuando no es cierto y viceversa. Si miráis el código de la clase Cliente, encontrareis el error, ya que es obvio, pero lo bueno es que el proyecto UnitTest, testea este método de la clase Cliente, usando un Mock del ServicioFicheros y el UnitTest detecta el error. Observad lo fácil que ha sido sustituir el ServicioFicheros por un Mock sin alterar la clase Cliente, gracias al uso del patrón Service Locator!
Saludos!!!
PD: Estooo... que me dejado de adjuntar el código de ejemplo!! :P Lo encontrareis aquí! :)

Referencias

Os dejo algunas referencias para su lectura por si os interesa profundizar un poco en el tema tratado:

lunes, 2 de junio de 2008

El método de la burbuja (para ordenar listas, claro).

MMmm... analizando los logs de google analytics, he visto que mucha (mucha de la poca se entiende xD), que entra al blog, lo hace a través de una búsqueda relacionada con... el algoritmo de ordenamiento de la burbuja! Así, que bueno... me he decidido a escribir algo sobre este algoritmo... al menos los pocos que llegan por aquí, que se queden contentos!! ;)

Por quien no conozca este algoritmo, diré que se trata de una forma no muy eficiente de ordenar los elementos de una lista. Eso sí, al menos tiene dos ventajas: és un método sencillo y además es un método sencillo. Y en que consiste???

Pues bueno, supongamos una lista de números, desordenada... por ejemplo 32,4,35,1 y queremos ordenarla de menor a mayor. Para ello cojemos el primer par de elementos (32 y 4) y:

  • Si el segundo es menor que el primero los intercambiamos
  • En caso contrario, los dejamos tal cual.
  • Repetimos el procedimiento, ahora con el segundo y tercer elemento de la lista... hasta llegar al final.
  • Luego volvemos a repetir todo el procedimiento, pero hasta llegar al penúltimo elemento... luego repetimos, pero llegamos hasta el antepenúltimo elemento, y así sucesivamente, hasta tener la lista ordenada.

En nuestro ejemplo (en negrita el par de elementos que comparamos y en cursiva los elementos que quedan fuera de la comparación):

32, 4, 35,1 => 4,32,35,1 => 4,32,35,1 => 4,32,1,35 => Repetimos desde el inicio, pero sin contar el último elemento

4,32,1,35 => 4,32,1,35 => 4,1,32,35 => Repetimos desde el inicio, pero sin contar los dos últimos elementos:

4,1,32,35 => 1,4,32,35 => Fin del algoritmo. Lista ordenada.

Bueno... el código en C# seria algo así como sigue (adaptación del código que podeis encontrar en "la tecla de escape"):

static void Burbuja(List<int> lst)

{

int iaux;

for (int i = 0; i < lst.Count - 1; i++)

{

for (int j = 0; j < lst.Count - i - 1; j++)

{

if (lst[j] > lst[j + 1])

{

iaux = lst[j];

lst[j] = lst[j + 1];

lst[j + 1] = iaux;

}

}

}

}


Qué sencillo, no???? Pues bueno... vamos ahora a hacer que el método ordene, no solo listas de ints, si no listas de cualquier tipo... uno podría pensar que igual basta declarar el método genérico... Lamentablemente si declaramos el método como:

static void Burbuja<T>(List<T> lst)

{

T iaux = default(T);

// El resto todo igual que antes...


El método no compila... el compilador se queja diciendo: Operator '>' cannot be applied to operands of type 'T' and 'T'. Este error es debido a que los parámetros genéricos son tratados como de tipo object... y el operador > no está definido para tipos object. Además usar una clausula where, no nos sirve en este caso (ya que where nos permite indicar que el parámetro template debe satisfacer una determinada interfaz, pero los operadores siempre se declaran como static en C# y por lo tanto nunca pueden declararse en una interfaz).

Entonces... estamos atrapados? Pues no... la solución pasa por usar un parámetro extra en nuestro método Burbuja, que le indique como debe ordenar los elementos. Es decir, un parámetro que le indique a nuestra función Burbuja, que método debe usar (en lugar de operador '>') para determinar si un elemento es "mayor" que otro. Además, eso es incluso más lógico que usar el operador '>', puesto que imaginemos que tenemos una lista de perros... igual nos interesa ordenarlos por tamaño, pero quizá lo queremos hacer por raza o color del pelo... entonces si tenemos que pasar un parámetro que apunte a un método... necesitamos un delegate.

Así deberiamos declarar un delegate que fuese algo parecido a:

delegate int Comparador<T> (T a1, T a2);


En este caso asumiremos que el delegate nos devuelve 1 si a1 es "mayor" que a2 y -1 si es al revés.

Y usar nuestro método Burbuja como sigue:

delegate int Comparador<T> (T a1, T a2);

class Program

{

static int ComparaDoubles(double d1, double d2)

{

if (d1 == d2) return 0;

return d1 > d2 ? 1 : -1;

}

static void Main(string[] args)

{

List<double> lista = new List<double>() { 32.3, 4.1, 35.2, 1.09 };

Burbuja(lista, new Comparador<double>(Program.ComparaDoubles));

}

static void Burbuja<T>(List<T> lst, Comparador<T> comparador)

{

T iaux = default(T);

for (int i = 0; i < lst.Count - 1; i++)

{

for (int j = 0; j < lst.Count - i - 1; j++)

{

if (comparador(lst[j], lst[j + 1]) == 1)

{

iaux = lst[j];

lst[j] = lst[j + 1];

lst[j + 1] = iaux;

}

}

}

}

}


Ale... solo teneis que cambiar el método al que apunta el delegate y podeis ordenar lo que os de la gana!

Bueno... y ahora que os he soltado el rollo... dos cosillas:

  1. El framework ya define un delegate como nuestro "Comparador", y se llama Comparison.
  2. La clase List<T> tiene un método Sort, que espera como parámetro... un delegate de tipo Comparison... :)

O sea que si quereis ordenar listas, lo mejor es algo del estilo:

lista.Sort (delegate (double d1, double d2)

{

if (d1 == d2) return 0;

return d1 > d2 ? 1 : -1;

} );


Bueno... espero que al menos los que aterrizais por aquí buscando información sobre el método de la burbuja... os haya servido este post!

Nos leemos! ;)

miércoles, 14 de mayo de 2008

Culturilla: Covarianza en genéricos

Este es el primer post de una serie (espero que larga) de posts de culturilla: cada cuando pueda iré publicando posts con información sobre cosas interesantes (a mi criterio, claro :P) sobre .NET y que no está de más saber... vamos, como su nombre indica, un poco de culturilla sobre .NET.
Y para empezar, un tema que tarde o temprano todo el mundo se termina planteando: son covariantes los genéricos de .NET? O, lo que es lo mismo: si los perros son animales, entonces las listas de perros son listas de animales?

Todos estamos acostumbrados a hacer algo como esto:

class Animal { }

class Perro : Animal { }

class Program

{

static void Main(string[] args)

{

Domestica(new Perro());

}

static void Domestica(Animal a)

{

}

}


Es decir, pasar un Perro a un método cuya firma especifica que espera un Animal. Esto además es lógico puesto que si la clase Perro deriva de la clase Animal, entonces todos los perros son animales.
Dicho esto, uno esperaria entonces que el siguiente código funcionase también:

class Animal { }

class Perro : Animal { }

class Program

{

static void Main(string[] args)

{

DomesticaVarios(new List<Perro>());

}

static void DomesticaVarios(List<Animal> a)

{

}

}


Pero si compilamos este código, veremos que no compila. Visual Studio se nos quejará con un mensaje parecido a: cannot convert from 'System.Collections.Generic.List' to 'System.Collections.Generic.List'

Así que, aunque todos los Perros sean Animales, resulta que una lista de Perros NO es una lista de Animales. Es por eso que se dice que los genéricos en .NET no son covariantes.

Una vez que hemos comprobado esto, la pregunta es si esto es lógico o no... Hombre, a simple vista podríamos decir, que es lógico: de la misma manera que los métodos que trabajan con Animales funcionan con Perros, los que trabajen con una lista de Animales, deberían hacerlo con una lista de Perros... Entonces por que no funciona?

Primero por como funcionan los genéricos: List<Animal> y List<Perro> son dos clases completamente distintas, que tienen la misma relación que List<Animal> y List<Florecilla> por decir algo.
Otra razón que podríamos argumentar es para mantener la coherencia de la lista, si pudiesemos pasar una
List<Perro> a un método que espera una List<Animal> nada impide hacer esto:

static void Domestica(List<Animal> a)

{

a.Add(new Gato());

}


(Suponed que la clase Gato deriva de Animal).

En este caso, tenemos un List<Perro>... donde uno de sus elementos no es un Perro!!! No se si nunca habeis juntado varios perros con un gato, pero os puedo decir que se arma una de buena!

Este segundo argumento podria ayudarnos a entender un poco la no covarianza de genéricos en .NET... y digo solo un poco, porque para liar las cosas... los arrays si que son covariantes. Así, que si todavía quereis ver lo que pasa cuando se junta un gato con varios perros, siempre podeis hacer lo siguiente:

static void Main(string[] args)

{

Perro[] p = new Perro[10];

Domestica(p);

}

static void Domestica(Animal[] a)

{

a[1] = new Gato();

}


Y ahora la pregunta es... que hay en el array p, después de llamar a Domestica()????
Pues la respuesta es que el programa casca que da gusto con una ArrayTypeMismatchException, así que bueno... seguimos sin poder juntar perros con gatos :)

Saludos!