Buscar este blog

lunes, 18 de abril de 2011

Usar o no DBLinq

La respuesta rápida: no lo uses.

DBLinq es un proyecto muy interesante nos permite accesar a diferentes tipos de bases de datos de la misma forma en accesamos a SQL Server con Linq a SQL Server de .Net Framework, tiene una herramienta (DBMetal.exe) que nos crea un conjunto de clases equivalente a las que se crean para Linq a SQL con Visual Studio o sqlmetal.exe.
Para mi lo mejor que tiene DBLinq es que solo cambiando la cadena de conexión y en ocasiones cambiando un poco el código generado por DBMetal.exe podemos cambiar de tipo de servidor (por ejemplo de SQL Server a MySql sin modificar el programa en lo más mínimo, pues la cadena de conexión se puede cambiar por ejemplo en el app.config o web.config, por lo que si escribes tu programa usando DBLinq tienes soporte instantaneo para todas las bases de datos que soporta este framework y las que soporte en el futuro.
Entonces por que recomiendo que no lo uses?
Aquí vienen las malas noticias, el proyecto tiene errores que lo hacen simplemente inutilizable, simplemente DBMetal.exe no puede manejar cualquier base de datos, basta que tengamos alguna asociación de tablas que no le guste al programa y nos mandara un error mientras que sqlmetal.exe puede manejar la misma base de datos sin problemas.
Aun así con un poco de trabajo se puede crear las clases necesarias y usar DBLinq en cualquier base de datos, sin embargo nos topamos con el siguiente problema: los querys regresan datos incorrectos.
Así es, lo corrobore con Linq a SQL, Linq a objetos y otros frameworks e indudablemente DBLinq regresa datos incorrectos, solo funciona para las bases de datos y querys mas triviales.

Más aun el proyecto a abril del 2011 parece abandonado y no ha habido cambios en el código durante más de un año.
La buena noticia es que el proyecto ahora se incluye como parte de Mono y los desarrolladores de Mono arreglan los errores que se reportan con mucha rapidez, yo pretendo trabajar un poco con ellos ya que en realidad el proyecto tiene un potencial muy grande y ya me gustaría estarlo usando en todos mis proyectos actuales.

En conclusión: De momento no cambies todavía a DBLinq pero mantén un ojo en el proyecto debido a su potencial.

Para aprender más sobre Linq visita:
Lista de artículos acerca de Linq

jueves, 14 de abril de 2011

LibCurlNet: alternativa a WebRequest

Curl es una librería escrita en C para utilizar diversos protocolos de red y LibCurlNet es un wrapper de la librería para usarla en .Net Framework es una buena alternativa para las clases que derivan de WebRequest sobre todo si quieres usar un protocolo no so soportado por WebRequest, los protocolos que soporta esta API son HTTP, HTTPS, FTP, FTPS, SCP, SFTP, TFTP, TELNET, LDAP, DICT y FILE.
Además WebRequest a veces falla sin ninguna razón aparente y también en estos casos podrías usar Curl como una alternativa.
Se puede descargar desde el sitio de LibCurlNet.
LibCurlNet nos presenta dos formas de uso principalmente la llamada easy y la llamada multi, En esta entrada hablare de la interfaz easy con HTTP que como su nombre nos indica es muy sencilla de usar, un poco más complicado que WebRequest pero no demasiado.
El API se accede en el espacio de nombres SeasideResearch.LibCurlNet y lo primero que hay que hacer es inicializar el API con la llamada al método Curl.GlobalInit y al terminar de usar el API se usa necesariamente el método Curl.GlobalCleanup, es muy importante hacer estas llamadas solo una vez en toda la vida del programa de lo contrario obtendremos errores.
Ahora pasamos a usar la clase Easy para bajar un archivo html con la operación GET (también se soporta POST y PUT).
El wrapper usa casi directamente el API en C y no esta muy orientada a objetos pero aún así resulta muy sencilla de utilizar en general usamos la funcíon SetOpt del objeto Easy para establecer las opciones de transferencia incluyendo la URL, proxy, headers, seguimiento de redirecciones, etc y utilizamos la llamada a Perform para obtener el resultado, aquí es donde esta la mayor diferencia entre WebRequest y CURL, la llamada a Perform por si misma lleva a cabo toda la transferencia, pero lo único que nos da como resultado es código que nos indica si se realizo la transferencia o no y la causa del fallo, para obtener los datos tenemos que escribir una función que usara el objeto Easy (como un delegado) para transmitirnos los datos en forma de un arreglo de bytes y es nuestra responsabilidad decidir que hacemos con esos bytes.
También podemos obtener el código http de la respuesta con la función GetInfo.
Si queremos remplazar o eliminar los headers que manda Curl automáticamente  podemos agregar estos headers con o sin valor y se eliminaran o remplazaran en la transferencia.
El mismo objeto Easy se puede usar cuantas veces queramos para diferentes URLs y el mismo tratara de reutilizar la misma conexión a menos que se indique lo contrario, cuando se termine de usar debemos llamar a easy.Cleanup antes de la llamada a Curl.GlobalCleanup de lo contrario se provocara un error.
A continuación les dejo el ejemplo en C# que explica el proceso por si mismo.


static void Main(string[] args) {
    Curl.GlobalInit((int)CURLinitFlag.CURL_GLOBAL_ALL);
    Easy easy = new Easy();
    easy.SetOpt(CURLoption.CURLOPT_URL, "http://localhost/");
    easy.SetOpt(CURLoption.CURLOPT_FOLLOWLOCATION, true);
    easy.SetOpt(CURLoption.CURLOPT_CONNECTTIMEOUT, 10);
    easy.SetOpt(CURLoption.CURLOPT_TIMEOUT, 90);
    easy.SetOpt(CURLoption.CURLOPT_PROXY, "http://localhost:8080");
    easy.SetOpt(CURLoption.CURLOPT_USERAGENT, "My Download");
    easy.SetOpt(CURLoption.CURLOPT_ENCODING, "gzip,deflate");
    easy.SetOpt(CURLoption.CURLOPT_FAILONERROR, true);
    Slist headers = new Slist();
    headers.Append("Pragma:");
    headers.Append("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7");
    easy.SetOpt(CURLoption.CURLOPT_HTTPHEADER, headers);
    List<byte> buffer = new List<byte>();
    Easy.WriteFunction writer = new Easy.WriteFunction(OnWriteData);
    easy.SetOpt(CURLoption.CURLOPT_WRITEFUNCTION, writer);
    easy.SetOpt(CURLoption.CURLOPT_WRITEDATA, buffer);
    easy.Perform();
    int code = 0;
    easy.GetInfo(CURLINFO.CURLINFO_RESPONSE_CODE, ref code);
    easy.Cleanup();
    Curl.GlobalCleanup();
    string content = "";
    using(MemoryStream mStream = new MemoryStream(buffer.ToArray())) {
        using(StreamReader reader
        = new StreamReader(mStream, Encoding.UTF8)) {
            content = reader.ReadToEnd();
        }
    }
    Console.WriteLine("Status: " + code.ToString());
    Console.WriteLine(content);
    Console.WriteLine("leido");
    Console.ReadLine();
 
}
private static Int32 OnWriteData(Byte[] buf, Int32 size, Int32 nmemb
, Object extractData) {
    List<byte> buffer = (List<byte>)extractData;
    buffer.AddRange(buf);
    return size * nmemb;
}