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;
}

miércoles, 30 de marzo de 2011

Validando esquemas xml con .Net Framework

Uno de los objetivos de los esquemas xml (archivos .xsd) es poder validar que un archivo xml cumpla con las reglas que se especifican en el esquema, .Net tiene el API necesaria para realizar esta validación y es muy sencillo.
Consideremos el siguiente esquema:

   1:  <?xml version="1.0" standalone="yes"?>
   2:  <xs:schema id="Peliculas"
   3:                       targetNamespace="ProbadorConsola"
   4:                       xmlns:xs="http://www.w3.org/2001/XMLSchema"
   5:                       xmlns="ProbadorConsola"
   6:                       elementFormDefault="qualified">
   7:    <xs:element name="Peliculas">
   8:      <xs:complexType>
   9:        <xs:choice minOccurs="0" maxOccurs="unbounded">
  10:          <xs:element name="Pelicula">
  11:            <xs:complexType>
  12:              <xs:sequence>
  13:                <xs:element name="Titulo" type="xs:string" minOccurs="0" />
  14:                <xs:element name="Director" type="xs:string" minOccurs="0" />
  15:                <xs:element name="Estrenado" type="xs:string" minOccurs="0" />
  16:                <xs:element name="Actores" minOccurs="0" maxOccurs="unbounded">
  17:                  <xs:complexType>
  18:                    <xs:sequence>
  19:                      <xs:element name="Actor" minOccurs="0" maxOccurs="unbounded">
  20:                        <xs:complexType>
  21:                          <xs:sequence>
  22:                            <xs:element name="Nombre" type="xs:string" minOccurs="0" />
  23:                            <xs:element name="Nacimiento" type="xs:string" minOccurs="0" />
  24:                            <xs:element name="Roles" minOccurs="0" maxOccurs="unbounded">
  25:                              <xs:complexType>
  26:                                <xs:sequence>
  27:                                  <xs:element name="Rol" minOccurs="0" maxOccurs="unbounded">
  28:                                    <xs:complexType>
  29:                                      <xs:sequence>
  30:                                        <xs:element name="NombrePelicula" type="xs:string" minOccurs="0" />
  31:                                        <xs:element name="NombreRol" type="xs:string" minOccurs="0" />
  32:                                      </xs:sequence>
  33:                                    </xs:complexType>
  34:                                  </xs:element>
  35:                                </xs:sequence>
  36:                              </xs:complexType>
  37:                            </xs:element>
  38:                          </xs:sequence>
  39:                        </xs:complexType>
  40:                      </xs:element>
  41:                    </xs:sequence>
  42:                  </xs:complexType>
  43:                </xs:element>
  44:              </xs:sequence>
  45:            </xs:complexType>
  46:          </xs:element>
  47:        </xs:choice>
  48:      </xs:complexType>
  49:    </xs:element>
  50:  </xs:schema>

Y el contenido xml que queremos validar:

   1:  <Peliculas xmlns="ProbadorConsola">
   2:      <Pelicula>
   3:      <Titulo>Mazinger</Titulo>
   4:      <Director>Jackie Chan</Director>
   5:      <Estrenado>1975-03-19T00:00:00</Estrenado>
   6:      <Actores>
   7:        <Actor>
   8:          <Nombre>John Wayne</Nombre>
   9:          <Nacimiento>1915-10-23T00:00:00</Nacimiento>
  10:          <Roles>
  11:            <Rol>
  12:              <NombrePelicula>Mazinger</NombrePelicula>
  13:              <NombreRol>Estrella</NombreRol>
  14:            </Rol>
  15:          </Roles>
  16:        </Actor>
  17:      </Actores>
  18:    </Pelicula>
  19:  </Peliculas>

Lo primero que debemos hacer es validar que el documento contenga el espacio de nombres del esquema si no lo contiene la validación fallara diciéndonos que el documento es valido aun cuando en realidad no cumpla las reglas del esquema.
El código para encontrar el espacio de nombres (c#):

   1:  XDocument peliculas = XDocument.Load("peliculas.xml");
   2:  XPathNavigator nav = peliculas.CreateNavigator();
   3:  nav.MoveToFollowing(XPathNodeType.Element);
   4:  IDictionary<string, string> ns
   5:      = nav.GetNamespacesInScope(XmlNamespaceScope.All);
   6:  bool schemaFound = false;
   7:  foreach(KeyValuePair<string, string> namespaces in ns) {
   8:      if(namespaces.Value.CompareTo("ProbadorConsola") == 0)
   9:          schemaFound = true;
  10:  }
  11:  if(!schemaFound) {
  12:      Console.WriteLine("Esquema no encontrado");
  13:      return;
  14:  }
Ahora si podemos proceder a validar el documento con el esquema que puede estar en un archivo local o en Internet:

   1:  XmlSchemaSet schema = new XmlSchemaSet();
   2:  schema.Add("ProbadorConsola", "peliculas.xsd");
   3:  peliculas.Validate(schema, null);
   4:  Console.WriteLine("Esquema valido");
   5:  Console.ReadLine();

Hacemos notar que si utilizas Linq a XSD todo esto lo hace en una sola linea de código al cargar el documento.

Para aprender más sobre el uso de XML en .Net Framework visita:
Lista de artículos acerca del uso de XML en .Net Framework

sábado, 26 de marzo de 2011

Instalar Linq a XSD

En una entrada anterior ya vimos lo que se puede hacer con Linq a XSD pero dejamos el proceso de instalación pendiente ya que es un poco complicado y merece una entrada independiente.
Linq a XSD es muy útil y no deberíamos detenernos en su uso debido a las pocas complicaciones que tiene su instalación sobre todo tomando en cuenta que es un proyecto de Microsoft y probablemente se incluya en versiones futuras de Visual Studio.
Bueno lo primero es descargarlo desde el proyecto de Linq a XSD en Codeplex y colocar los archivos descargados en una carpeta preferentemente dentro de la carpeta de nuestra solución, en nuestro ejemplo se colocara en la carpeta Components\LinqToXsd\bin en la raíz de nuestra solución y añadimos los archivos en una carpeta de solución solo para recordarnos donde están y no es un paso obligatorio.
Ahora abrimos las propiedades del proyecto en que vamos a usarlo y en la pestaña Build Events en el recuadro Pre-build event command line colocamos el siguiente texto:

SET LINQTOXSDBINDIR=$(SolutionDir)Components\LinqToXsd\bin

Cuidando que la ruta apunte a donde pusimos los archivos.


Ahora necesitamos modificar el archivo csproj de la solución (Linq a XSD solo funciona en C-Sharp, pero puedes hacer una DLL que después utilizaras en VB.Net), para esto descargamos la solución, en el explorador de la solución escogemos el proyecto que estamos usando, click derecho y Unload Project, click derecho y Edit proyecto.csproj.
Vamos al final del archivo y después del cierre del último elemento <propertygroup> ponemos este código:

   1:  <PropertyGroup>
   2:      <LinqToXsdBinDir Condition="'$(LinqToXsdBinDir)' == ''">$(SolutionDir)Components\LinqToXsd\bin</LinqToXsdBinDir>
   3:  </PropertyGroup>

Nótese que al pegar el código Visual Studio lo formatea poniéndole lineas nuevas alrededor de la ruta, debemos modificar esto de tal forma que la quede igual que en el código de ejemplo de lo contrario tendremos errores. A continuación muestro la forma en que NO debe quedar la modificación

   1:  <PropertyGroup>
   2:      <LinqToXsdBinDir Condition="'$(LinqToXsdBinDir)' == ''">
   3:          $(SolutionDir)Components\LinqToXsd\bin
   4:      </LinqToXsdBinDir>
   5:  </PropertyGroup>

Falta introducir otro código en el mismo archivo, también al final del archivo después de el cierre del último elemento <import> colocamos el siguiente código:

   1:  <Import Project="$(LinqToXsdBinDir)\LinqToXsd.targets" />

Listo recargamos la solución y al archivo .xsd para el que queremos crear las clases le cambiamos el Build Action a LinqToXsdSchema compilamos y se nos generan las clases que necesitamos, es necesario notar que las clases se encuentran en el espacio de nombres indicado en el atributo targetNamespace del esquema xml (.xsd) y no en el de nuestro proyecto por lo que debemos buscar las clases en ese espacio de nombres.

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

Para aprender más sobre el uso de XML en .Net Framework visita:
Lista de artículos acerca del uso de XML en .Net Framework

viernes, 18 de marzo de 2011

Cobertura de código (Code Coverage) con pruebas unitarias de Visual Studio

Una de las funciones que tiene los proyectos de pruebas de Visual Studio es la Cobertura de Código o Code Coverage en ingles, esta función nos permite saber que porcentaje del código de nuestro proyecto estamos probando lo cual es muy importante pues puede haber errores en el código que no estamos probando y esta función nos da una idea de que pruebas nos faltan por escribir.

Para habilitar la cobertura de código previo requisito es que tengamos una versión de Visual Studio que tenga soporte para proyectos de prueba, al crear nuestro proyecto de prueba Visual Studio crea automáticamente un archivo llamado LocalTestRun.testrunconfig en una carperta Elementos de la solución (Solution Items) directamente bajo la solución para habilitar la cobertura de código hacemos doble click en este archivo y nos aparecerá la ventana de configuración de las pruebas en esta ventana escogemos la sección Cobertura de Código y nos aparece una lista con las dll's y ejecutables que produce nuestra solución debemos marcar los elementos para los que queremos habilitar la cobertura de código aplicamos los cambios cerramos y listo ya tenemos habilitada la cobertura de código en nuestras pruebas.


Para obtener los resultados ejecutamos las pruebas que queremos analizar y abrimos el panel Resultado de Cobertura de Código (Code Coverage Results) aquí vemos una lista que nos muestra detalle los porcentajes de código que estamos probando pudiendo expandir la lista hasta saber exactamente que parte del código se probo en que porcentaje.


En la imagen podemos ver que solo se probo el 4 por ciento del código con lo cual sabemos que nos falta mucho por probar, por supuesto es un ejemplo solo demostrativo.

Para aprender más acerca de las pruebas unitarias con .Net Framework visita:
Lista de artículos acerca de pruebas unitarias con .Net Framework

miércoles, 16 de marzo de 2011

Integrar NUnit a Visual Studio

Hay varias formas de integrar NUnit a Visual Studio, aquí mostrare la más sencilla y la que me parece la más conveniente.
Siguiendo las instrucciones del sitio de NUnit agregamos una herramienta personalizada a Visual Studio y le agregamos los parámetros necesarios para ejecutar NUnit en el proyecto actual estos datos son:

Titulo: NUnit
Comando: C:\Program Files\NUnit 2.5.1\bin\net-2.0\nunit.exe
ajustando la ruta a donde tenemos instalado NUnit
Argumentos: $(ProjectDir)$(ProjectFileName)
Directorio Inicial: $(ProjectDir)bin/Debug/



Eso es todo seleccionamos en el editor un archivo que este en un proyecto de pruebas NUnit y en el menú de herramientas seleccionamos NUnit y se abrira NUnit usando el proyecto de pruebas seleccionado, nótese que tiene que estar abierto y activo en el editor algún archivo que pertenezca a un proyecto de pruebas de NUnit de lo contrario nos marcara un error.

La otra opción es mucho mejor ya que integra los proyectos de pruebas de NUnit con la interfaz de Visual Studio sin necesidad de abrir el ejecutable de NUnit y mostrando los resultados dentro de la pantalla de Visual Studio, el requisito es que tengamos una versión de Visual Studio que soporte proyectos de prueba.
Esto se logra usando el componente NUnitForVS que podemos bajar de CodePlex y funciona para las versiones 2008 y 2010 de Visual Studio.
Después de instalar el complemento tenemos que modificar los proyectos de NUnit en nuestras soluciones lo que debemos hacer es descargar el proyecto de la solución (Unload Project desde el explorador de soluciones) y editar el archivo csproj tenemos que añadir la siguientes lineas:

<projecttypeguids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</projecttypeguids>

al final de la primer sección <propertygroup> que encontremos en el archivo.
Después de esto ya estamos listos para ejecutar nuestras pruebas abrimos la ventana Vista de Pruebas (Test View) y encontraremos nuestras de NUnit mezcladas con las pruebas de Visual Studio (si es que tenemos alguna) e identificadas por un icono de una N al pricipio:


Ejecutamos las pruebas y obtenemos los resultados en el panel de resultados de las pruebas:


Para aprender más acerca de las pruebas unitarias con .Net Framework visita:
Lista de artículos acerca de pruebas unitarias con .Net Framework