viernes, 21 de enero de 2011

Powershell - Libro Gratuito de Microsoft



















La gente de Microsoft publicó hace algún tiempo un libro electrónico en inglés sobre Windows PowerShell.

El libro ha resultado ser un éxito. Sus casi 50 páginas ayudan a aquellos que quieren conocer Windows PowerShell.

A continuación ustedes tienen los enlaces correspondientes:


Alguna documentación interesante mas ejemplos, scripts y artículos en los siguientes links:
http://technet.microsoft.com/es-ar/library/ee221100%28en-us%29.aspx
http://technet.microsoft.com/es-es/scriptcenter/dd742419

jueves, 9 de diciembre de 2010

¿Fue buena idea usar AES256 con el archivo INSURANCE de Wikileaks?

Por Fernando Acero

Desde hace tiempo, estoy recibiendo correos de gente que me pregunta sobre la posibilidad de decodificar el archivo INSURANCE de Wikileaks, que presuntamente (el nombre lo pone) está codificado usando el algoritmo AES256. Al margen de las discusiones morales, prácticas y éticas, derivadas de decodificar a las bravas un archivo que presuntamente sirve para salvar la vida de alguien, nos podemos centrar en el estudio de la parte técnica de este asunto de la decodificación del AES, que todo hay que decirlo, es un asunto que me interesa mucho más...

De todos modos, ¿alguien se imagina lo que me pasaría si yo dijera en este momento: “Señores, durante una noche de insomnio y usando mi batería de tarjetas NVIDIA, he logrado decodificar el archivo INSURANCE de Wikileaks”?. Puede que en la puerta de mi casa encontrase tantos agentes secretos vigilando mis movimientos y tanta gente atacando mis sistemas informáticos, como periodistas en la final del mundial de fútbol y eso no me apetece en absoluto ¿y a ustedes?.

El ALGORITMO AES

El algoritmo AES (Advanced Encryption Satandard), también conocido como Rijndael, es un sistema de cifrado por bloques simétrico, pensado para sustituir al obsoleto DES y optimizado para las transmisiones seguras de mensajes a través de las redes de telecomunicaciones. AES es muy rápido, tanto en las implementaciones de software, como en las de hardware y además de ser relativamente fácil de implementar, requiere poca memoria para realizar los cálculos. Como nuevo estándar de cifrado, se está utilizando a gran escala por todo el mundo, lo que le parece muy interesante a los amigos de asuntos conspiratorios. El AES/Rijdael, fue desarrollado por dos criptólogos Belgas, llamados Daemen y Rijmen, cuando eran estudiantes de la Universidad Católica de Leuven.

La principal diferencia entre el AES y el DES al que sustituye, es que el AES usa una red de sustitución-permutación (serie de sustituciones y permutaciones, que se suceden unas a otras sobre una matriz), en lugar de una red de Feistel. El AES utiliza un bloque de tamaño fijo de 128 bits (originalmente podía usar bloques de varios tamaños) y las claves pueden ser de 128, 192 y 256 bits. Al igual que el DES, el procedimiento de codificación se basa en una operación básica llamada "ronda", que se repite un número fijo de de veces dependiendo del tamaño de la clave. Así, con las claves de 128 bits, se usan 10 rondas, 12 rondas con las de 192 bits y 14 rondas, para las claves de 256 bits. AES trabaja sobre una estructura conocida como el "estado AES", que es simplemente una reordenación del bloque básico, usando una matriz de 4×4 y por lo tanto, es un sistema que tiene una descripción matemática bastante simple, aunque para la mayoría de los comunes mortales, es más sencillo verlo como operaciones con bytes en una matriz de datos.

Los bloques básicos del AES son:

  • SubBytes - Una sustitución no lineal en el estado AES.
  • ShiftRows - Realiza un desplazamiento sobre las filas del estado AES.
  • MixColumn - Mezcla columnas del estado de AES, haciendo cada celda una combinación de otras celdas.
  • AddRoundKey - Mezcla la clave con el estado AES.

Una codificación AES consiste en la realización de los siguientes pasos sencillos:

1. Ronda Inicial:

  • AddRoundKey

2. R-1 Rondas:

  • SubBytes
  • ShiftRows
  • MixColumns
  • AddRoundKey

3. Ronda final

  • SubBytes
  • ShiftRows
  • AddRoundKey

El proceso de decodificación sin embargo, es más complicado que con el DES, en el que simplemente había que volver a “codificar” un mensaje ya “codificado”, usando por supuesto, la misma clave. En el caso del AES, es necesario definir las operaciones inversas para ShiftRows, SubBytes y MixColumns. Hay que señalar, que para la operación AddRoundKey no se requiere una inversa, puesto que basta con aplicarla otra vez con la misma clave, para obtener su inversa.

SEGURIDAD REAL DEL AES

Se dice que un sistema criptográfico está roto cuando existe algún ataque más rápido que una búsqueda exhaustiva (ataque por fuerza bruta), aunque este ataque sea solamente teórico, y no sea viable por la cantidad de datos, tiempo, o memoria necesaria.

Algunas personas han dicho que el AES está roto por los resultados obtenidos con una clave de 64 bits, que fue llevado a cabo por distributed.net, pero la realidad es que solamente fue un ataque por fuerza bruta de una clave muy pequeña de 64 bits, por lo que no lo podemos considerar como una ruptura del AES.

De hecho, el AES, a pesar de ser un algoritmo público y de uso público, está considerado como la NSA (Agencia de Seguridad Nacional de los EEUU) desde el año 2003, como algoritmo seguro para proteger información clasificada de nivel SECRETO usando claves de 128 bits y de ALTO SECRETO, si se usan claves de 192 o 256 bits. No deja de sorprender, teniendo en cuenta el amor-odio del Gobierno de los Estados Unidos con los sistemas de cifrado, que el gran público pueda tener acceso a un sistema de cifrado considerado apto por la NSA, para proteger información sensible del más alto nivel, lo que no deja de levantar muchas suspicacias.

LOS ATAQUES POSIBLES

La forma más asequible de ver si es posible realizar un ataque a un codificador de bloques, es intentar atacarlo mediante la reducción del número de rondas utilizadas en la codificación. Si recordamos, el AES usa 10 rondas para las claves de 128 bits, 12 rondas para claves de 192 bits, y 14 rondas para claves de 256 bits. Hasta el año 2005, los mejores ataques conocidos tuvieron éxito sobre versiones reducidas a 7 rondas para claves de 128 bits, de 8 rondas para las claves de 192 bits, y de 9 rondas, para las claves de 256 bits.

Sin embargo, también es cierto que en estos ataques se evidencia una escasa diferencia entre las rondas reales y las de los mejores ataques conocidos, por lo que con una pequeña mejora en los ataques, cabría la posibilidad de romper un cifrado que use todas las rondas. Está claro, la mejor vacuna para el problema, sería aumentar el número de rondas sin cambiar el algoritmo. Sin embargo, esta solución también tendría un impacto en la eficiencia del algoritmo y sobre todo, en la actualización de los sistemas basados en hardware. Hay que señalar, que se conocen algunos ataques exitosos sobre determinadas implementaciones del AES, que se basan en el canal auxiliar, pero estos ataques no atacan al algoritmo en sí mismo, sino a una implementación específica del mismo, por lo que tampoco son aplicables a la decodifcación del archivo de Wikeleaks.

En esta línea de investigación, en el año 2009, Alex Biryukov y Dmitri Khovratovich, de la Universidad de Luxemburgo, publicaron este interesante artículo, con dos ataques contra el algoritmo de cifrado AES, que mejoran de forma impresionante los resultados anteriores. Biryukov y Khovratovich anunciaron un ataque contra AES de 256 completo, es decir, con sus 14 rondas. El ataque tiene una complejidad computacional de solamente 2^96 operaciones, es decir, romper la seguridad de un AES256/14 sería tan difícil como probar 2^96 claves. No cabe la menor duda de que está fuera del alcance de la mayoría de los mortales, pero ver un algoritmo de 256 bits con una fortaleza equivalente a la de uno de solamente 96 bits, no dice mucho a favor del algoritmo. Pero tranquilidad, que esta afirmación tiene trampa, solamente funciona con determinadas claves “podridas”, es decir, con una clave de cada 34.000 millones. ¿Habrá usado Wikileaks una de esas claves podridas de forma voluntaria o involuntaria?. Sin duda es una buena pregunta, ya que no sabemos exactamente lo que pretende Wikileaks con este archivo, si que no lo abra nadie, o que solamente lo abran los que están “retratados” en él, para darles miedo.

Sin embargo, el otro ataque de Biryukov y Khovratovich, aunque es menos “efectivo” que el anterior, funciona con cualquier clave y demuestra otros datos preocupantes sobre el AES. El ataque contra el AES-128/10, tendría una complejidad matemática de 2^123 datos (claves), 2^176 en tiempo y de 2^152 en memoria, así que aunque curioso, esto no es nada preocupante por el momento. Sin embargo, el ataque contra el AES-256/14 es mucho más efectivo, ya que solamente se necesitan 2^119 en datos y tiempo y 2^77 en memoria. Dicho de otro modo, el AES-256 tiene la misma fortaleza que un teórico AES-119/14, por debajo del AES-123/10 que se obtendría con el ataque a un AES-128/10 y esto, con independencia de la clave que usemos. Es evidente que esto sigue estando fuera del alcance de cómputo de la mayoría de los mortales, pero ¿lo está del alcance de una superpotencia?, sobre todo, si tenemos en cuenta además, que los autores dicen que pueden mejorar el ataque al AES-256/14 a una complejidad de solamente 2^110,5?. Dicho esto, aunque la NSA dijo que el AES-128/10 era seguro para los SECRETOS y el AES-192/12 y el AES-256/14 para los ALTOS SECRETOS, lo cierto es que visto lo anterior, el AES-128/10 es más seguro que el AES-256/14 en igualdad de condiciones.

Pero si lo anterior no nos preocupa demasiado, hay otro interesante artículo, fechado el 19 de agosto de 2009, y firmado por unos reputados Alex Biryukov, Orr Dunkelman, Nathan Keller, Dmitry Khovratovich, y Adi Shamir. En este articulo comentan algo mucho más preocupante sobre el AES-256, ya que lograron ataques contra el AES-256/9 con una complejidad matemática de solamente 2^39 operaciones, contra el AES-256/10 con una complejidad de solamente 2^45 y consideran que el AES-246/11, podría tener una complejidad de solamente 2^70, valores todos ellos, muy por debajo de los logrados por Biryukov Khovratovich.

Está claro, no se está hablando del AES-256/14, pero es evidente, que hay un problema y grave con el AES-256, aunque solamente hayan llegado a las 10 rondas y especulado un poco sobre las 11 rondas. De nuevo me pregunto ¿está esto fuera del alcance de la NSA con todos sus medios técnicos y sus miles de matemáticos en plantilla?.

Bueno, para ser justos, hay otra trampa en el plantemiento de Shamir y sus amigos, estos ataques no son prácticos con el archivo de Wikileaks, pero solamente desde nuestro lado, ya que el que el que tiene los mensajes en claro (aunque no sepa exactamente los que son). Es decir, el Gobierno de los EEUU, lo tiene complicado, pero no tanto como nosotros, que no tenemos nada para empezar a trabajar. Los ataques anteriores se denominan de “claves relacionadas”, es decir, que se supone que el criptoanalista dispone de acceso a una serie de textos en claro, que han sido codificados mediante varias claves distintas, las cuales, tienen una relación específica entre ellas.

Parece demostrado en el caso del AES, que a mayor tamaño de la clave, menor es la dificultad para romperla. Algo que puede significar que no se eligió un número de rondas adecuado para el tamaño de cada clave, puede que por un compromiso entre la seguridad y la velocidad, pero que al final, ha comprometido la seguridad las versiones de AES 192/12 y 256/14. Los dos “paper” que hemos revisado anteriormente dicen lo mismo con distintas palabras, en este momento, es más seguro el AES-128/10 que el AES-256/14 y en términos estrictos lo podemos considerar roto, desde los primeros resultados de Biryukov y Khovratovich, ya que su fortaleza en ciertas condiciones es inferior a la de un ataque por fuerza bruta.

Teniendo en cuenta que Bruce Shneier ya recomendaba en su blog el día 30 de julio de 2009, que se usase AES-128/10 en lugar de AES-256/14, es curioso y no menos inquietante, que los responsables de Wikileaks, tan preocupados por la seguridad como están, hayan decidido proteger su archivo “salvavidas” con un roto AES-256.

Si me hubieran preguntado, si buscase la seguridad absoluta de que el archivo no sería abierto en un tiempo razonable y mi vida fuera en ello, yo no hubiera optado por el AES-256/14 ni por asomo, que hablando claro, en este momento, lo podemos considerar seguro, aunque menos seguro que el DES que pretende sustituir.

"Copyleft 2010 Fernando Acero Martín. Verbatim copying, translation and distribution of this entire article is permitted in any digital medium, provided this notice is preserved. Quotation is allowed."

miércoles, 15 de setiembre de 2010

sábado, 11 de setiembre de 2010

Inversion de Control (IOC) usando Castle Windsor - Justificación

Algunos cuantos artículos explicando el por qué necesitamos utilizar IOC (inversion of control) , en estos ejemplos tenemos la implementación de IOC usando Castle Windsor:

Un excelente artículo que explica claramente los por qué y que es el que primero hay que leer para empezar a entender este tema:
http://leomicheloni.blogspot.com/2008/07/qu-es-la-inversin-de-control-inyeccin.html

Otros artículos interesantes de leer:

http://ihenrysmith.blogspot.com/2010/03/contenedor-ioc.html
http://blog.darioquintana.com.ar/category/ioc/
http://kartones.net/blogs/coco/archive/2009/11/27/inversi-243-n-de-control-ioc.aspx

La página del proyecto Castle:
http://www.castleproject.org/

sábado, 7 de agosto de 2010

Cual es el password predeterminado del Windows Storage Server 2008??

Como poseedor de una subscripción MSDN me descargué el Windows Storage Server 2008 e inmediatamente me armé una máquina virtual para probarlo.

El tema es que cuando finalizó la instalación me apareció la ventana de login y no tenía la menor idea cual era la pass de logueo.

Bueno, luego de arduas investigaciones (llamé a un amigo que ya lo había instalado) pude obtener la tan ansiada password: wSS2008! (el signo de admiración es parte del password también).

lunes, 16 de noviembre de 2009

Como leer un archivo pdf desde un aplicativo web form / asp.net

Aquí les dejo un método que les permitirá leer un archivo pdf (adobe) desde un aplicativo Web Asp.NET.

Deben utilizar el siguiente imports:

using System.Net;

A continuación el método:

private void LeerArchivoPdf(string NombreArchivoPDF)
{
string ruta = NombreArchivoPDF;
WebClient client = new WebClient();
Byte[] buffer = client.DownloadData(ruta);
if (buffer != null)
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-length", buffer.Length.ToString());
Response.BinaryWrite(buffer);
}
}

Hugo Bernachea
MCT - MCSD

viernes, 16 de octubre de 2009

A namespace does not directly contain members such as fields or methods - App.Config

Si les aparece el siguiente error en el app.config:
A namespace does not directly contain members such as fields or methods
O su equivalente es castellano, y ustedes verifican y se aseguran que su app.config está correctamente configurado, si verifican el contenido del app.config un par de veces y ven que el contenido del app.config es ok, lo mejor que pueden hacer es copiar el contenido del app.config en un archivo de texto, guardar dicho archivo de texto, eliminar el app.config y volver a agregar un app.config en blanco y nuevamente copiar el contenido del app.config anterior. Con eso se suele corregir ese error.

Función IsNumeric en C#

Csharp (C#) no cuenta con una función isnumeric al estilo Visual Basic, pero se pueden implementar diferentes soluciones para lograr el objetivo, uno es hacer una función como la siguiente:

public bool IsNumeric(object Expression)
{
bool esnumero;
double returnNumero;

esnumero= Double.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any,System.Globalization.NumberFormatInfo.InvariantInfo, out returnNumero);
return esnumero;
}

La otra solución es crear una librería (Dll) en visual basic.NET y directamente referenciarla en C#, que yo pienso que es quizás la mejor opción.

sábado, 1 de agosto de 2009

.NET 3.5 - Usando el Nuevo tipo SqlDbType.Structured para pasar parámetros de tipo Table a Stored Procedures en SQL Server 2008

En SQL Server 2008 se ha agregado la posibilidad (largamente esperada) de pasar un parámetro de tipo Table a un Stored Procedure, pueden ver una explicación aquí:
http://sqldata.blogspot.com/2009/08/mejoras-en-t-sql-de-sql-server-2008-el.html

La pregunta es como hacer desde .NET 3.5 para invocar este tipo de stored procedures, lo cual se resuelve fácilmente con el nuevo sqltype de tipo Structured

El código que viene a continuación es un ejemplo de lo dicho, como verán todo esto es código conocido, la única novedad es que pasamos directamente un datatable completo al value del parámetro, definido como Structured, veamos el ejemplo:

//creo un data table para almacenar algunos registros de ejemplo
DataTable dtClientes = new DataTable("Clientes");
DataColumn dcNombre = new DataColumn("nombre", typeof(string));
DataColumn dcApellido = new DataColumn("apellido", typeof(string));
DataColumn dcEmail = new DataColumn("Email", typeof(string));
dtClientes.Columns.Add(dcNombre);
dtClientes.Columns.Add(dcApellido);
dtClientes.Columns.Add(dcEmail);
//agrego un cliente
DataRow drCustomer = dtClientes.NewRow();
drCustomer["nombre"] = "aaa.net";
drCustomer["apellido"] = "XYZ";
drCustomer["Email"] = "info@kyriosdata.com.ar";
dtClientes.Rows.Add(drCustomer);
//Agrego otro cliente
drCustomer = dtClientes.NewRow();
drCustomer["nombre"] = "bbb.net";
drCustomer["apellido"] = "XYZ";
drCustomer["Email"] = "info@kyriosdata.com.ar";
dtClientes.Rows.Add(drCustomer);
//Y otro cliente mas
drCustomer = dtClientes.NewRow();
drCustomer["nombre"] = "ccc.net";
drCustomer["apellido"] = "XYZ";
drCustomer["Email"] = "info@kyriosdata.com.ar";
dtClientes.Rows.Add(drCustomer);
//Creo la conexion, recuerde modificar el connection string
// y modifique server e indique SU servidor
// y modifique en base de datos e indique SU base de datos
SqlConnection conn = new SqlConnection("server=.;database=Ejemplo;Integrated Security=true");
conn.Open();
//Lo tradicional, creamos un comando que invoque al store "Agrega clientes"
// que está definido y se pueden encontrar en el enlace siguiente:
// http://sqldata.blogspot.com/2009/08/mejoras-en-t-sql-de-sql-server-2008-el.html
SqlCommand cmdCustomer = new SqlCommand("AgregaClientes", conn);
cmdCustomer.CommandType = CommandType.StoredProcedure;
//Aquí en realidad se encuentra lo único distinto con respecto
// a la lógica que veníamos usando en .NET
// y es crear el parámetro pero usando el nuevo sqldbtype Structured
// el cual puede recibir un datatable completo
// el s.p. matchea con un parámetro de tipo table, ver el link
SqlParameter paramCustomer = cmdCustomer.Parameters.Add("@ClientesTVP", SqlDbType.Structured);
paramCustomer.Value = dtClientes;
//Ejecutamos
cmdCustomer.ExecuteNonQuery();

Y si revisamos la tabla Clientes debiéramos encontrar los nuevos registros agregados a la tabla cliente.

Nuevamente y por si a alguien se le escapó el detalle, la información acerca de este nuevo tipo de parámetros como asimismo la definición del Stored Procedure se encuentra en el siguiente enlace:

http://www.sqlexperto.com.ar/index.php?topic=20.msg21#new





martes, 21 de julio de 2009

Diferencias entre Eventos y Delegados - En qué son distintos?

Eventos versus Delegados (Events vs Delegates)

Es la típica pregunta acerca de la diferencia entre eventos y delegados, considerando que uno siempre podría imitar la funcionalidad de un evento utilizando un delegado. Esto considerando que un evento siempre está relacionado a un delegado.

Un evento es parecido a un multicast delegate en algún sentido.

Veamos el siguiente ejemplo donde tenemos msgNotifier (evento) y msgNotifier2 (delegado simple) que aparentan comportarse exactamente igual en todo sentido.

using System;

namespace EventAndDelegate
{
delegate void MsgHandler(string s);

class Class1
{
public static event MsgHandler msgNotifier;
public static MsgHandler msgNotifier2;
[STAThread]
static void Main(string[] args)
{
Class1.msgNotifier += new MsgHandler(PipeNull);
Class1.msgNotifier2 += new MsgHandler(PipeNull);
Class1.msgNotifier("test");
Class1.msgNotifier2("test2");
}

static void PipeNull(string s)
{
return;
}
}
}


Si vemos el código IL para el método Main vemos que ambos msgNotifier y msgNotifier2 son usados de la misma manera.

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 95 (0x5f)
.maxstack 4
IL_0000: ldsfld class EventAndDelegate.MsgHandler EventAndDelegate.Class1::msgNotifier
IL_0005: ldnull
IL_0006: ldftn void EventAndDelegate.Class1::PipeNull(string)
IL_000c: newobj instance void EventAndDelegate.MsgHandler::.ctor(object,
native int)
IL_0011: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0016: castclass EventAndDelegate.MsgHandler
IL_001b: stsfld class EventAndDelegate.MsgHandler EventAndDelegate.Class1::msgNotifier
IL_0020: ldsfld class EventAndDelegate.MsgHandler EventAndDelegate.Class1::msgNotifier2
IL_0025: ldnull
IL_0026: ldftn void EventAndDelegate.Class1::PipeNull(string)
IL_002c: newobj instance void EventAndDelegate.MsgHandler::.ctor(object,
native int)
IL_0031: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0036: castclass EventAndDelegate.MsgHandler
IL_003b: stsfld class EventAndDelegate.MsgHandler EventAndDelegate.Class1::msgNotifier2
IL_0040: ldsfld class EventAndDelegate.MsgHandler EventAndDelegate.Class1::msgNotifier
IL_0045: ldstr "test"
IL_004a: callvirt instance void EventAndDelegate.MsgHandler::Invoke(string)
IL_004f: ldsfld class EventAndDelegate.MsgHandler EventAndDelegate.Class1::msgNotifier2
IL_0054: ldstr "test2"
IL_0059: callvirt instance void EventAndDelegate.MsgHandler::Invoke(string)
IL_005e: ret
} // end of method Class1::Main


Si vemos en el MSDN keywords list vemos que los event son solo modificadores (modifier).

La pregunta es que cosa exactamente modifican?

Valor agregado de un evento
Eventos e interfaces

Un evento puede ser incluido en la declaración de una interface mientras que un campo no.

interface ITest
{
event MsgHandler msgNotifier; // compila
MsgHandler msgNotifier2; // error CS0525: Interfaces cannot contain fields
}

class TestClass : ITest
{
public event MsgHandler msgNotifier; // cuando se implementa una interface se debe implementar el evento también.
static void Main(string[] args) {}
}


Invocation de un evento

Un evento solo puede ser invocado en la clase en la que se declaró, mientras que un delegado puede ser invocado desde cualquier parte.

Ejemplo:

using System;

namespace EventAndDelegate
{
delegate void MsgHandler(string s);

class Class1
{
public static event MsgHandler msgNotifier;
public static MsgHandler msgNotifier2;

static void Main(string[] args)
{
new Class2().test();
}
}

class Class2
{
public void test()
{
Class1.msgNotifier("test"); // error CS0070: The event 'EventAndDelegate.Class1.msgNotifier' can only appear on the left hand side of += or -= (except when used from within the type 'EventAndDelegate.Class1')
Class1.msgNotifier2("test2"); // compiles fine
}
}
}

Esta restricción es muy fuerte y aún las clases derivadas no pueden invocar dicho evento (salvo un método protected virtual que lo dispare).

Accesores de Eventos
Eventos disponen de métodos add y remove.
Esto es similar al get y set de las properties.

Firma del evento

el .NET framework agrega una restriction en la firma de los delegados que pueden ser usados como eventos. La firma tienen que ser en este estilo foo(object source, EventArgs e), donde source es el objeto que dispara el evento y e contiene información específica a este evento.

Estas serían a mi entender algunas diferencias entre eventos (events) y delegates (delegados)

domingo, 21 de junio de 2009

Como exponer los eventos RowUpdated y RowUpdating en un TableAdapter?

Bueno, después de dar un par de vueltas e investigar un poco, acá les dejo la solución a como exponer los eventos RowUpdated y RowUpdating de un TableAdapter de los generados con diseñador de Dataset fuertemente Tipados.

Tanto en C# 2005 como en C# 2008 tienen que ir al Dataset tipado (xsd).
Identifican al TableAdapter (NO el datatable) que van a modificar y clickean con boton izquierdo.
Van a la ventana de propiedades para el tableadapter y ponen la propidad ConnectionModifier en PUBLIC.

Después clickean con el botón derecho en el mismo TableAdapter y van a la opción Ver Código (View Code) y en la ventana de código agregan la clase parcial necesaria para incorporar el código que expone el dataadapter interno.

El código a continuación es un ejemplo de como debiera queda la clase

namespace WinCon.DataSet1TableAdapters //obviamente acá va el namespace de ustedes
{
using System.Data;
using System.Data.SqlClient; //acá va el provider de la base que ustedes están usando
// en caso que no sea SQL Server

public partial class EjemploTableAdapter //de nuevo, el nombre exacto de su tableadapter
{
public System.Data.SqlClient.SqlDataAdapter Adapter2 //el nombre que se les ocurra
{
get
{
this.Adapter.SelectCommand = this.CommandCollection[0];
return this.Adapter;
}
}
}
}

Hasta acá la modificación, si lo estuvieran invocando por ejemplo desde un windows forms, podrían ejecutar lo siguiente (ojo que ahora el código que viene a continuación está adentro de un windows forms que utiliza al tableadapter).

DataSet1TableAdapters.EjemploTableAdapter da = new WinCon.DataSet1TableAdapters.EjemploTableAdapter();
DataSet1 ds = new DataSet1();


public Form1()
{
//atacho los eventos y digo que lo gestionan
// los métodos metodo y metodo2 respectivamente.
da.Adapter2.RowUpdating += metodo; //fijensé que uso la propiedad Adapter2
// que creé adentro del TableAdapter.
da.Adapter2.RowUpdated += metodo2;
InitializeComponent();
}


Espero que a alguien le sea de utilidad.

Hugo Bernachea
http://www.linkedin.com/in/bernachea

viernes, 19 de junio de 2009

Firebird con Visual Studio 2005

********* Consejo Dado "AS IS" "ASI COMO ESTA", sin garantias y bajo la total y absoluta responsabilidad de quien lo aplica, como todos los consejos, tipos y sugerencias dados en este sitio *********

Firebird como base de datos "free" no es tan conocida como otras bases de datos mas populares como MySQL y PostgreSQL, pero lo cierto es que Firebird tiene una serie de características que la hacen muy interesante a la hora de realizar desarrollos de programas "empaquetados".
Una de las características es que esta base puede ser embebida en el producto final, con lo cual no se le instala un servidor al cliente. Además Firebird tiene Stored Procedures, Triggers, Funciones y todas las características que presentan las bases de datos comerciales y que MySQL recién está empezando a adoptar desde su ultima versión. Obviamente Firebird es muy superior a SQL Lite e incluso es superior a las versiones express de SQL Server y su licencia comercial permite utilizarlo incluso en programas comerciales sin restricciones.

La idea de utilizarlo con .NET viene pronto a las manos y por lo tanto voy a describir como hacerlo funcionar en Visual Studio 2005.

Pasos a seguir:
1. Ir a la página de Firebird y descargar el provider para .NET 2.
2. Descargue el Visual Studio 2005 SDK (NO el SDK del framework please) desde el sitio de descargas de Microsoft. Recuerden que el SDK del Visual Studio NO es parte de la instalación, es una descarga adicional.
3. Verifique y en caso de no estar previamente agragado, agregue el provider de firebird para .net 2 (el archivito FirebirdSQL.Data.FirebirdClient.dll) a la Global Assembly Cache (GAC) con gacutil.exe -i FirebirdSQL.Data.FirebirdClient.dll.
4. Ejecute gacutil.exe /l FirebirdSql.Data.FirebirdClient y fíjese los números que indica esta ejecución, particularmente el número de version, el publickeytoken y cultura.
5. Ubique el machine.config y fíjese en los siguientes tags:
Desdpués de configuration ->configSections agregue lo siguiente (todo seguido)

add <section name="firebirdsql.data.firebirdclient" type="System.Data.Common.DbProviderConfigurationHandler, System.Data, Version=SU_NUMERO_DE_VERSION, Culture=neutral, PublicKeyToken=EL_PublicKeyToken_DE_SU_DLL_EN_SU_GAC">

6. En <system.data> -> <dbproviderfactories> agregar
<add name="FirebirdClient Data Provider" invariant="FirebirdSql.Data.FirebirdClient" description=".Net Framework Data Provider for Firebird" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient, Version=ACA_VA_SU_NUMERO_DE_VERSION, Culture=neutral, PublicKeyToken=DE_NUEVO_ACA_VA_SU_PUBLIC_KEY_TOKEN">

7. Abra el archivo FirebirdDDEXProvider.reg y reemplace la variable %Path% con la ruta exacta donde se encuentra la dll del provider, por ejemplo C:\Program Files\FirebirdClient, recuerde de agregar doble barra, por ejemplo C:\\Program Files\\FirebirdClient. Guarde el archivo .reg y con un doble click agregue esa información en el registro.

Si hizo todo de la manera correcta ya tiene disponible la opción para abrir el VS 2005 y usar firebird como cualquier otra base de datos, incluso agregando la conexion en el server explorer.

lunes, 5 de enero de 2009

Haciendo Generadores de Codigo con CodeDom

A los que están interesados en realizar sus propios generadores de código en .NET (C# o VB.NET), les dejo un ejemplo para utilizar Codedom (los imports mínimos son: System.CodeDom y System.CodeDom.Compiler )
Lo bueno de CodeDom es que permite generar código de manera genérica pero de implementación concreta, esto es, podemos hacer generadores de código para cualquier de los lenguajes de .NET (c++, C#, Vb.NEt, etc).

Aquí vá el ejemplo que pueden utilizar y probar, este código genera un string con el código de una clase en C# y en VB, con una propiedad llamada ID y un constructor predeterminado. Ideal para comenzar a probar y experimentar.

Dim ns As CodeNamespace 'definiendo un namespace para nuestra clase

Private Sub GeneraClase
'defino un namespace base
ns = New CodeNamespace("PrimerCodeDom")

'agrego los imports correspondientes
'aca pueden agregar todos los imports necesarios
ns.Imports.Add(New CodeNamespaceImport _
("System"))
ns.Imports.Add(New CodeNamespaceImport _
("System.Diagnostics"))
ns.Imports.Add(New CodeNamespaceImport _
("System.Text"))

'creo la clase en si misma
Dim clase As New CodeTypeDeclaration("Clase_Clientes")
'agrego la clase a la colección de tipos
ns.Types.Add(clase)

'defino un campo privado

Dim campo As New CodeMemberField("integer", "_ID")
campo.Attributes = MemberAttributes.Private

'agrego el miembro privado a la clase

clase.Members.Add(campo)

'defino un campo público

Dim p As New CodeMemberProperty()

' le doy un nombre a la propiedad
' ID en este caso
p.Name = "ID"

' lo hago público
p.Attributes = MemberAttributes.Public
p.Type = New CodeTypeReference("System.Int32") 'es integer
p.HasGet = True
p.HasSet = True 'si fuese false, sería solo lectura

'esto que viene es obligatorio
'tengo que decirle que cosa devuelve el get de la propiedad
p.GetStatements.Add( _
New CodeMethodReturnStatement( _
New CodeFieldReferenceExpression( _
New CodeThisReferenceExpression(), "_ID")))
'esto también es obligatorio
'tengo que decirle como se asigna el valor del set
p.SetStatements.Add(New CodeDom.CodeAssignStatement( _
New CodeFieldReferenceExpression( _
New CodeDom.CodeThisReferenceExpression, "_ID"), _
New CodeDom.CodePropertySetValueReferenceExpression))

'agrego la propiedad a la clase
clase.Members.Add(p)

'defino un constructor público

Dim constructor As New CodeConstructor()
constructor.Attributes = MemberAttributes.Public
clase.Members.Add(constructor)

'defino los providers para los lenguajes en los que voy a generar mi clase
Dim csProvider As New Microsoft.CSharp.CSharpCodeProvider
Dim vbprovider As New VBCodeProvider

'en .net 3.5 este código tira un warning por obsoleto,
'pero igual funciona perfecto.
Dim codigo As ICodeGenerator

codigo = vbprovider.CreateGenerator()
Dim vbCod As String = generaCode(codigo)

codigo = csProvider.CreateGenerator
dim csCod as String = generaCode(codigo)

'en este punto, en las variables vbCod y csCod
'tienen el código de la clase correctamente generada.

End Sub

'metodo complementario
Private Function generaCode(ByVal CodeGenerator As ICodeGenerator) As String

Dim options As New CodeGeneratorOptions()

' defino la identación del código
options.IndentString = Space(3)

' creo un StringWriter
Dim sb As New StringBuilder()
Dim sw As StringWriter = New StringWriter(sb)

' genero
CodeGenerator.GenerateCodeFromNamespace(ns, sw, options)

' devuelvo el string con el código generado
Return sb.ToString()
End Function

Una utilidad interesante podría ser utilizar este código para generar un mapeador de clases contra tablas de una base de datos, para lo cual debemos recorrer las tablas de una base de datos, ver código SQL aquí: http://sqldata.blogspot.com/2009/01/como-obtener-todas-las-tablas-de-una.html y por cada tabla recorrer los campos con el Script SQL listado aquí: http://sqldata.blogspot.com/2009/01/como-obtener-todos-los-campos-de-una.html y aplicar el codigo codedom correspondiente para generar un mapeador de clases contra tablas.
O sea, por cada tabla generar la clase en codedom y por cada campo generar dentro de la clase correspondiente las propiedades que necesitemos.

Con eso tienen lo necesario para generarse un mapeador de clases si se ponen manos a la obra.


Hugo Bernachea

viernes, 26 de diciembre de 2008

Donde están las bases de ejemplo de SQL Server 2008??

Si instalaron SQL Server 2008 y notaron que no se instaló ninguna base de datos de ejemplos, a no desesperar, las mismas se encuentran en el sitio opensource de Microsoft, codeplex, mas exactamente en:

http://www.codeplex.com/MSFTDBProdSamples/Wiki/View.aspx?title=Installing%20Databases&referringTitle=Home

martes, 23 de diciembre de 2008

Utilidades Imprescindibles para .NET

Aquí publico un listado de utilidades, frameworks y otros programas que yo considero imprescindibles para los desarrolladores .NET y espero que ustedes puedan agregar las que crean que faltan en el listado:

1) .NET Reflector: http://www.red-gate.com/products/reflector/
Un clásico. Permite descompilar y analizar ensamblados .NET, analizar las clases constituyentes, ver sus métodos, MSIL.























.

2) Autocode: http://www.devprojects.net/
Gratuito.
Es un add-in para Visual Studio .NET que automatiza tareas repetitivas y permite generar código, refactorizar, ejecutar acciones del IDE o cualquier otro comando. Altamente recomendable, una herramienta imprescindible para .NET.





















3) CodeSmith: http://www.codesmithtools.com/
Otro clásico, templates (plantillas) para generar código en distintos lenguajes y con distintos objetivos. ( C#, Java, VB, PHP, ASP.NET, SQL, etc.).
No es gratis, pero es muy util.

4) .NET Memory Profiler: http://memprofiler.com/
Tampoco es gratis, pero permite determinar y optimizar el uso de la memoria en programas realizados en .NET.

5) QuickCode.NET: http://www.mobzystems.com/
Además de QuickCode, Gratuito, la página tiene un montón de utilidades mas, muy interesantes la mayoría de ellas, recomiendo mirar la página.

6) Snippet Compiler: http://www.sliver.com/dotnet/SnippetCompiler/
Gratuito.

7) FxCop: http://blogs.msdn.com/fxcop/archive/2008/08/19/fxcop-1-36-released.aspx
Gratuito. Otro imprescindible y clásico.
FXCop es una herramienta de análisis de código para .NET desarrollada por GotDotNet. Lee ensamblados (dll o exe) directamente para hacer el análisis.
En la actualidad está migrándose a la MSDN y se está integrando con la versión 2008 del Microsoft Visual Studio .Net (ORCAS), pero se puede usar desde cualquier versión de Visual Studio.

8) NUnit: http://www.nunit.org/index.php
Gratuito. La implementación .NET del Framework de testing de java unit, imprescindible en la arquitectura TDD.

9) NDoc: http://ndoc.sourceforge.net/
Gratuito. Genera documentación para los ensamblados .NET.

10) NAnt: http://nant.sourceforge.net/
Gratuito. Portado del Ant de Java, permite automatizar los procesos de compilación y Builds de los aplicativos.

11) PInvoke.NET add-in: http://www.pinvoke.net/
Permite encontrar y determinar las llamadas a win32 y apis desde código manejado (.Net).

12) Regulator: http://sourceforge.net/projects/regulator/
http://regulator.sourceforge.net
Herramienta de testeo de expresiones regulares, muy bueno.

13) Asp.NET Version Switcher:
http://www.denisbauer.com/NETTools/ASPNETVersionSwitcher.aspx

14) Resharper: http://www.jetbrains.com/resharper/
No solo refactoriza código, es una herramienta multipropósito.

15) NHibernate: http://www.hibernate.org/343.html
Framework de persistencia de datos, heredado del Hibernate de Java, con soporte para múltiples bases de datos. Ya se que existe Linq, pero todavía está verde, en cambio Hibernate ya viene con un camino recorrido y además es una tecnología abierta multiplataforma, multi-base de datos. Además parece que Linq to SQL está moribundo, de modo que yo me sigo quedando con Hibernate, además como también programo algunas cosas en Java, con Hibernate puedo programar exactamente lo mismo en un lenguaje (C#) que en otro (Java).

Hasta aquí la lista, espero que puedan agregar las herramientas que crean conveniente.


Hugo Bernachea
http://www.linkedin.com/in/bernachea
MCSD / MCDBA / MCT

domingo, 26 de octubre de 2008

Nothing y DBNull.Value en Visual Basic.NET

Que diferencia hay entre Nothing y DBNull.value???

Mucha gente está bastante confundida acerca de este tema y no son pocos ciertamente los que lo están. Vamos a tratar de esclarecer en forma rápida y concreta este tema.

La palabra clave Nothing sirve para especificar o asignar que un variable de tipo referencia no está apuntando a nada, no está instanciado objeto alguno para dicha variable.

DBNull.Value en cambio es un objeto que se usa para indicar que un tipo (type) de un campo de base de datos es de valor nulo (Null).

Yo creo que esta común confusión tiene su origen en las versiones anteriores de VB, ya que contaba con un sinnumero medio de especificar estados de variables (nothing, empty, null, ismissing, "", etc).


jueves, 2 de octubre de 2008

Casteo Dinámico de tipos (type)

Estaba haciendo un código con un toque de reflection.
Necesitaba un casteo entre tipos que se iban a resolver solamente en tiempo de ejecución, de modo que el casteo común y corriente no me servía. Después de dar un par de vueltas fuí a los mas simple, la clase Convert y su método ChangeType, tal como aparece a continuación.

string tipo = "System.Int16";
object objeto1 = "345";
object objeto2 = Convert.ChangeType(objeto1, Type.GetType(tipo));
Type t = objeto2.GetType(); // y aca tengo el tipo del system.int16 nuevamente

Comentarios:
objeto.GetType devuelve el tipo de un objeto existente.
gettype(type) devuelve el tipo de un tipo indicado especificamente
y
Type.GetType(String) devuelve el tipo que le indicamos en el string.

domingo, 21 de setiembre de 2008

Generación de Código con MyGeneration

Generadores de Codigo

Un generador de código permite agilizar el desarrollo de aplicaciones, yo lo estoy utilizando con un proyecto pequeño para ver que resultados obtengo.
Hasta ahora he logrado ahorrar tiempo y a la vez programar dentro de todo algo prolijo, es una buena forma de no caer en la típica programación con toda la logica pegada a la interfaz al estilo VB6 cuando necesitas hacer algo rápido. Asi queda algo elegante sin que ello nos involucre horas y horas de programar capas.
La aplicación que utilice para hacer esto se llama MyGeneration esta aplicación permite utilizar distintos templates que escriben código, vos podes armar el tuyo o usar alguno de los que ofrece entre ellos dOOdads y NHibernate, el último es muy conocido en el mundo de java.
Yo opte por probar con dOOdads, que por medio de una jerarquia de herencia te permite crear clases que mapean contra las tablas de tu base de datos para que después puedas usarlas de esta forma:

// Load and Save
Employees emps = new Employees();
if(emps.LoadByPrimaryKey(42))
{
emps.LastName
= "Just Got Married";
emps.Save();
}

// Add a new record
Employees emps = new Employees();
emps.AddNew();
emps.FirstName
= "Mr.";
emps.LastName
= "dOOdad";
emps.Save();



// After save the identity column is already here for me.
int i = emps.EmployeeID;
Les comento a grandes rasgos los pasos que hay que hacer para que salga andando:
1) bajar MyGenerator desde sourcefoge que es donde esta la última version del generador y del template.(acá el link http://sourceforge.net/projects/mygeneration )
2) Una vez instalado el programa necesitaras tener una base de datos bonita y lista para mapear hacia objetos.
3) La arquitectura de oddododos (o como se escriba) tiene los siguientes modulos:
a- un proyecto que tiene las clases bases que van a implementarse luego por el generador de código
b- los procedimientos almacenados que utilizan las clases para guardarse en la base de datos
c- un conjunto de vistas en la base de datos que debes crear para utilizar datos relacionados de forma eficiente.
4) Entonces para que esto ande primero tenemos que agregar a nuestro proyecto el proyecto de arquitectura de dOOdads, el mismo se encuentra en C:\Program Files\MyGeneration\Architectures\dOOdads\CSharp para la version C#.
5) Una vez que elegimos cual es la base de datos a usar tenemos que marcar la clases de la carpeta C:\Program Files\MyGeneration\Architectures\dOOdads\CSharp\MyGeneration.dOOdads\DbAdapters que vamos a usar (ver los prefijos) para que compilen. Para ello la seleccionamos y en el cuadro de propiedades la maracamos para incluirla en el build.

En la imagen muestro las dos clases que abría que cambiar la propiedad "Build Action" para que compile un proyecto con base de datos SQL Server 2000 o 2005.

6) una vez que tenemos el proyecto referenciado, vamos a generar nuestras clases de negocio. Para ello iniciamos mygeneration configuramos la cadena de conexión hacia la base de datos que vamos a mapear y procedemos a buscar en el arbol de la izquierda los templates a usar.

7) para crear las clases de negocios usamos el template dOOdads Business Entity que se encuentra bajo la rama c# de dOOdas. Este template les genera clases abstractas, si quieren las concretas también hay que hacerlo con el mismo método.
La idea de las clases concretas bobas es que ahí metamos el código especifico de nuestras aplicaciones.
Si van a usar vistas para obtener datos relacionados con joins también se generan desde ese apartado.
8) Tambien necesitamos crear los procedimientos almacenados para eso elegimos la base de datos correspondiente en el arbol de template (por ejemplo Microsoft SQL Server) y corremos el template de dOOdad Stored Procedures. Esto escupe un monton de stores por cada tabla que son necesarios para correr las clases generadas por MyGeneration.
Aca esta bueno tocarlos un poco para que hagan lo que nosotros querramos, por ejemplo en mi caso modifique los deletes para que no borren sino que marquen un campo de baja, y toque también el procedimiento que trae todo para que solo traíga aquellos que no estan marcados como borrados.
TIP: si a cada columna le agregan un campo RowVersion de tipo timestamp, el template va a utilizarla para manejar la concurrencia de los updates y puede llegar a generarles una sentencia TSEQUAL que no compila en 2005, no se hagan drama cambienlo por un igual y sale con frítas.
9) Agregamos todo el código generado a nuestra solución de C#
10) Configuramos TransactionMgr para que obtenga una query string válida para nuestro aplicativo en la fúncion private IDbConnection CreateSqlConnection(BusinessEntity entity), donde pueden traerla directamente del app.config o web.config.

Y con eso ya tendríamos andando una elegante capa de datos completa en no mas de 30 minutos.
Cualquier cosa no duden en preguntar... en la página de mygeneration hay un pdf de 6 paginas que dice básicamente lo mismo que acá y esta práctico para ver como usar bien toda la interfaz que te da.
Por ejemplo tiene un generador dinámico de querys muy piola.

Eso es todo por ahora hasta la próxima espero que le sea útil a alguien....

nota original en: http://rodcode.blogspot.com/2007/08/generadores-de-codigo.html

sábado, 30 de agosto de 2008

Conversor de .NET a JAVA - Grasshopper

La empresa MainSoft (http://dev.mainsoft.com/) ha desarrollado una serie de productos, basicamente plugins para Visual Studio.NET, para convertir un aplicativo .NET en un aplicativo JAVA listo para ser instalado en Linux sobre un servidor Apache Tomcat.

Pueden encontrar el plugin listo para ser descargado en la página de MainSoft: http://dev.mainsoft.com/Default.aspx?tabid=177

Realmente este producto permite desarrollar en la herramienta de mayor conocimiento, usando el lenguaje de mayor experiencia y luego todo ese desarrollo migrarlo a Java en Linux con facilidad, incluso para aquellos que poseen escasa experiencia en esas plataformas.

Muy interesante !.

lunes, 14 de julio de 2008

Como manejar los eventos de botones creados dinámicamente en asp.net

Un amigo me consultó hace un par de días acerca de un problema que el estaba teniendo con una página en la que dinámicamente generaba unos botones, les atachaba los eventos click mediante addhandler pero en tiempo de ejecución la página aspx ignoraba olímpicamente dicha codificación.

La codificación era del siguiente estilo:


Dim btnBoton As New Button
btnBoton.Text = "Click en este botón"
Page.Controls.Add(btnBoton)


Una vez que el botón está en la página no hay forma de hacer que responda al evento click.

No podía creer que algo tan sencillo no funcionase, de modo que empecé a buscar en todo internet, aunque me imaginaba que si agregaba un campo oculto y registraba la propiedad correcta todo iba a funcionar.

Entonces, primero hay que registrar un campo oculto en la página.


Page.ClientScript.RegisterHiddenField("BotonOculto", "")


Despues definimos el botón en forma dinámica.


Dim miBoton As New Button
miBoton.Text = "Click en este boton"


Y el secreto agregar desde el lado servidor un attribute al lado cliente que directamente envie el submit de la página mas el botón clickeado


objButton.Attributes.Add("onClick", & _ "document.forms[0].BotonOculto.value='" & _
miBoton.UniqueID & "';document.forms[0].submit();")


Bien drástico y concreto, uso el Dom y envio el submit desde el evento onClick previamente registrado.

Finalmente agrego el control a la coleccion de controles de la página.


Page.Controls.Add(miBoton)


Lo unico que resta es tomar en el postback que genera dicho botón el valor del item correspondiente y listo.

Entonces en el postback:


If Page.IsPostBack Then
If Request.Item("botonOculto").Length > 0 Then
Response.Write("Usted clickeó en el botón " & _
Request.Item("botonOculto") )
End If
End If


Línea mas, línea menos, así es como debiera quedar la cosa.

Y problema resuelto !

martes, 8 de enero de 2008

configurando Web.Config para Web Parts

Recuerden que para trabajar con WebParts deben crear la base aspnetdb por medio del utilitario de línea de comando: aspnet_regsql
Una vez creada dicha base de datos debemos agregar las siguientes líneas en el web.config:






























(En caso de no poder visualizar la imagen clickear sobre la misma, lo cual provocará que se cargue la imagen por completo).

Con todo esto ya debieran funcionar nuestros webs con web parts

miércoles, 28 de noviembre de 2007

martes, 27 de noviembre de 2007