Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
domingo, 26 de julio de 2009

Lanzarote Tras un año duro (¡muy duro!), llegan de nuevo las vacaciones: tiempo de descansar un poco, disfrutar con la familia, formatearse mentalmente y recargar las pilas con vistas a comenzar un nuevo periodo tras el verano. Y todo ello alternando entre Sanlúcar de Barrameda, El Portil, y una escapada a Lanzarote que seguro que será una delicia. No me puedo quejar, la verdad.

Variable Not Found quedará, una vez más, a la deriva hasta que regrese dentro de unas semanas. Además, para evitar que los spammers se vengan a vivir aquí, desactivaré temporalmente el envío de comentarios anónimos, lamento las molestias que pueda causar.

Feliz verano, amigos. :-)

Publicado en: Variable not found.

lunes, 20 de julio de 2009

En la plataforma .NET existen distintas formas de hacer que una llamada a un método sea omitida bajo determinadas circunstancias. Por ejemplo, los métodos parciales permiten, en C# 3.0 y VB 9.0, que el compilador omita la llamada a funciones no implementadas. También existe la posibilidad de utilizar las clásicas directivas (como #if… #endif ) para incluir código cuando existan constantes de compilación.

Es menos conocida, sin embargo, la existencia del atributo ConditionalAttribute, que aplicado a un método hace que las llamadas a éste no sean incluidas en el ensamblado si no existe la constante de compilación cuyo nombre se indica en el parámetro.

Por ejemplo, explorando un poco el espacio de nombres System.Diagnostics, vemos que todos los métodos de la clase Debug, están adornados por este atributo así:

   1: [Conditional("DEBUG")]
   2: public static void WriteLine(string message)
   3: {
   4:     TraceInternal.WriteLine(message);
   5: }

Ahora, imaginad que tenemos un código que usa esta clase, por ejemplo de la siguiente manera:


   1: public static void Main(string[] args)
   2: {
   3:     for(int i=0; i < 1000; i++)
   4:     {
   5:         Debug.WriteLine("Iteración " + i);
   6:         ProcesaAlgoComplejo(i);
   7:         int j = ProcesaOtraCosa(i);
   8:         Debug.WriteLine("Obtenido " + j);
   9:         // ...
  10:     }
  11: }

Si compilamos en modo “debug” (o simplemente está definida la constante de compilación con dicho nombre), las llamadas a estos métodos serán omitidas en el ensamblado resultante, por lo que el código finalmente generado será totalmente equivalente a:


   1: public static void Main(string[] args)
   2: {
   3:     for(int i=0; i < 1000; i++)
   4:     {
   5:         ProcesaAlgoComplejo(i);
   6:         int j = ProcesaOtraCosa(i);
   7:         // ...
   8:     }
   9: }

Pero ojo, que se omiten tanto las llamadas al método como la evaluación de sus parámetros, y esto puede provocar errores difíciles de detectar. Por ejemplo, el siguiente código daría lugar a un bucle infinito de los de toda la vida ;-) si compilamos en modo “release”; sin embargo, compilando en “debug” funcionaría correctamente:

   1: int j = 0;
   2: while (j < 100)
   3: {
   4:     Console.WriteLine("Hey " + j);
   5:     Debug.WriteLine("Procesado " + (j++));  // <-- Esta línea desaparece cuando
   6:                                             //     compilamos en modo release!
   7: }

Aunque en el anterior ejemplo estamos jugando con la constante predefinida DEBUG, este atributo podemos utilizarlo con otras constantes, tanto existentes como personalizadas. Como muestra, podéis echar un vistazo a la definición de la clase System.Diagnostics.Trace, que vincula el uso de sus métodos a la existencia de la constante TRACE:


   1: public sealed class Trace
   2: {
   3:     // ...
   4:  
   5:     private Trace();
   6:     [Conditional("TRACE")]
   7:     public static void Assert(bool condition);
   8:     [Conditional("TRACE")]
   9:     public static void Assert(bool condition, string message);
  10:     [Conditional("TRACE")]
  11:     public static void Assert(bool condition, string message, string detailMessage);
  12:     [Conditional("TRACE")]
  13:     public static void Close();
  14:     [Conditional("TRACE")]
  15:     public static void Fail(string message);
  16:     [Conditional("TRACE")]
  17:     public static void Fail(string message, string detailMessage);
  18:     [Conditional("TRACE")]
  19:     public static void Flush();
  20:     [Conditional("TRACE")]
  21:  
  22:     //...
  23: }

Si vais a utilizar el atributo sobre vuestros métodos, condicionándolos a la existencia de constantes de compilación personalizadas, recordad que las constantes podéis definirlas:

  • desde las propiedades del proyecto en el IDE
  • en la línea de comandos del compilador (por ejemplo, /define:LOG)
  • variables de entorno del sistema operativo (set LOG=1)
  • en directivas sobre vuestro propio código (directiva #define LOG)

Eso sí, tened en cuenta que el método siempre será compilado e introducido en el ensamblado, son las invocaciones a éste las que son omitidas en caso de no existir la constante indicada.

Hay que tener en cuenta las siguientes observaciones para el uso del atributo Conditional:

  • Los métodos a los que se aplica no pueden tener tipo de retorno, es decir, serán void. Esto tiene bastante sentido, si pensamos en los efectos laterales que podría causar la desaparición de una invocación tras la cual se haga uso del valor retornado.
  • Sólo se pueden aplicar a métodos en clases o estructuras. Nada de interfaces (¡tampoco tendría mucho sentido!).
  • Si un método virtual está marcado como Conditional, las reescrituras de éste realizadas desde clases descendientes también lo estarán.  Es bastante lógico, puesto que así se mantienen las dependencias íntegras.
  • Si el atributo se aplica a un método, éste no puede ser un reemplazo del comportamiento de un antecesor (o sea, que no puede ser un override). También resulta muy lógico.

En resumen, se trata de un buen método para incluir código condicional en nuestros desarrollos, dependiente del contexto de compilación, evitando tener que usar directivas #if… #endif. Pero no lo olvidéis: cuidado con los efectos laterales citados.


Publicado en: Variable not found.

martes, 14 de julio de 2009

Formulario PDFUn post en .NET Answers me ha recordado que hace tiempo tenía pendiente escribir una entrada para comentar la técnica que he utilizado en más de una ocasión para generar documentos PDF desde mis aplicaciones .NET de forma muy sencilla, y que puede aplicarse en escenarios donde se conozca de antemano el diseño del documento a imprimir y sólo sea necesario introducir información concreta en espacios muy definidos. Un caso muy habitual es el rellenado de formularios o impresos, aunque usando un poco la imaginación seguro que podéis encontrarle muchas más utilidades.

La técnica consiste en crear, utilizando alguna herramienta de diseño como Adobe Acrobat, un documento PDF que contenga todos los contenidos estáticos del documento que deseamos generar. En cada zona donde queremos inyectar contenido deberemos introducir un campo de formulario (por ejemplo, “nombre”, “apellidos”, etc.) adaptando el tipo de letra, límites y las propiedades del campo que sean necesarias.

imageYa desde código el procedimiento será bien sencillo: abrimos la plantilla, introducimos los valores en cada uno de los campos, y hacemos con el documento resultante lo que nos convenga según la ocasión: enviarlo por email, salvarlo a disco, ofrecerlo para la descarga, etc.

Para conseguir estos objetivos utilizaremos iTextSharp, una adaptación para .NET de la librería iText, muy conocida en el mundo Java. Por tanto, en primer lugar, es necesario descargarla desde Sourceforge, y referenciarla en el proyecto desde el cual vamos a utilizarla.

El siguiente código implementa un método realiza el procedimiento descrito:

   1: public void FillPDF(string templateFile, Stream stream)
   2: {
   3:     // Abrimos la plantilla y creamos una copia, sobre
   4:     // la cual trabajaremos...
   5:     PdfReader reader = new PdfReader(templateFile);
   6:     PdfStamper stamp = new PdfStamper(reader, stream);
   7:  
   8:     // Introducimos el valor en los campos del formulario...
   9:     stamp.AcroFields.SetField("Nombre", "Juan");
  10:     stamp.AcroFields.SetField("Apellidos", "Rodríguez Méndez");
  11:  
  12:     // Fijamos los valores y enviamos el resultado al stream...
  13:     stamp.FormFlattening = true;
  14:     stamp.Close(); 
  15: }

Así, para almacenar la plantilla con los datos en un nuevo PDF, bastaría con invocar al método anterior de la siguiente manera:


   1: Stream file = new FileStream("FormularioRelleno.pdf", FileMode.Create);
   2: FillPDF("plantilla.pdf", file);

O si queremos que desde una aplicación ASP.NET el usuario pudiera descargarlo directamente, podríamos utilizar un código como el siguiente:



   1: protected void btnGenerarPDF_Click(object sender, EventArgs e)
   2: {
   3:     Response.Clear();
   4:     Response.ContentType = "application/pdf";
   5:     Response.AddHeader("content-disposition", "attachment;filename=Formulario.pdf");
   6:     FillPDF(Server.MapPath("Plantilla.pdf"), Response.OutputStream);
   7: }

Por último, sólo comentar que iTextSharp no sólo es útil para rellenar formularios, ni mucho menos. Se trata de una librería muy potente que permite la creación y edición al vuelo de documentos PDF completos, y dispone de un complejo amplísimo API que nos permite hacer casi de todo con ellos. Además, se distribuye bajo licencias LGPL y MPL, muy permisivas ambas, por lo que pueden ser utilizadas en prácticamente cualquier tipo de sistemas.

Para el que no se le apetezca teclear mucho, ahí va una solución para Visual Studio 2005 con dos proyectos, uno web y otro de consola, demostrando el funcionamiento.






Publicado en: Variable not found.

lunes, 13 de julio de 2009

… o algún arma química o biológica, que sepas que no puedes utilizar Google App Engine: estarías violando los términos de la licencia.

 image

“El uso del servicio debe cumplir con todas las leyes aplicables, reglamentos y ordenanzas, incluyendo cualesquiera leyes relativas a la exportación de datos o software. Usted acepta no usar el servicio en el diseño, desarrollo, producción, o uso de misiles o el diseño, desarrollo, producción, almacenamiento y uso de armas químicas o biológicas”

Así que, si es este tu caso, ya puedes ir buscando otro software. Y no lo vas a tener fácil, puesto que se trata de un párrafo que se incluye muy habitualmente en las licencias de aplicaciones.

Pues eso, mucho ojo. ;-D

Visto en: DevTopics: why-terrorists-hate-google-app-engine
Publicado en: Variable not found.

lunes, 6 de julio de 2009

image Hace unos meses, un usuario de StackOverflow planteaba una interesante cuestión: ¿qué debería saber un desarrollador para construir un sitio web público? Es decir, ¿cuáles son aquellos aspectos importantes que deben tenerse en cuenta a la hora de crear un site de calidad, desde el punto de vista técnico?

Tras un tiempo de respuestas, ideas y debates, otro usuario ha realizado una recopilación de los aspectos y sugerencias más votadas y los ha publicado en forma de lista categorizada, donde podemos encontrar muy buenas ideas a tener en cuenta en nuestros propios desarrollos, y que me he permitido traducir.

Muchos de los puntos son obvios y seguro que ya los estáis teniendo en cuenta, quizás otros son demasiado exagerados, y seguro que alguno de ellos ni siquiera os los habíais planteado. En cualquier caso el resultado es una relación interesante y muy a tener en cuenta para mejorar nuestros sitios web.

Interfaz y experiencia de usuario

  • Ser consciente de que los navegadores implementan los estándares de forma diferente y asegurarse de que el sitio web funciona razonablemente bien en la mayoría de los principales navegadores. Como mínimo, sería necesario probarlo con un navegador que utilice un motor reciente Gecko (Firefox), Webkit (Safari, Chrome y algunos navegadores móviles), las versiones soportadas de Internet Explorer, y Opera.
  • Tener en cuenta que el sitio web puede ser visitado utilizando medios distintos a los navegadores habituales, como por ejemplo teléfonos móviles, lectores de pantalla, o motores de búsqueda. Usar estándares de accesibilidad como WAI o Section508.
  • Considerar los mecanismos de actualización del sitio web para que estos procesos no afecten a los usuarios una vez que el sistema está en marcha y puedan producirse de forma suave y transparente. Por ejemplo, puede ayudar el mantener entornos de prueba paralelos, el uso de herramientas de control del código fuente, o mecanismos de builds automatizados.
  • No mostrar errores directamente al usuario.
  • No incluir en las páginas direcciones de correo de usuarios en texto plano, para evitar que sean bombardeados por los spammers.
  • Incluir límites razonables de utilización del sitio para evitar malos usos por parte de usuarios o procesos automáticos (como puede ser los virus). Por ejemplo, es razonable que un sistema de correo electrónico gratuito limite el número de mensajes diarios que puede enviar un usuario, aunque el número máximo sea muy alto; otro ejemplo podemos verlo en Google, que muestra un mensaje de error cuando detecta demasiado tráfico hacia sus servidores desde una única dirección IP.

Seguridad

  • Conocer la amplia guía de desarrollo OWASP, que  cubre la seguridad de sitios web de forma muy completa.
  • Conocer el fundamento de los ataques de inyección SQL y cómo prevenirlos.
  • Jamás confiar en los datos introducidos por los usuarios.
  • Evitar el almacenamiento de contraseñas en texto plano utilizando técnicas criptográficas como hashes y salts.
  • No intentes utilizar tu magnífico y elaborado sistema de autenticación; es bastante probable que existan fallos impredecibles de los que sólo te darás cuenta después de haber sido hackeado.
  • Usar SSL/HTTPS en las páginas de identificación de usuarios y, en general, en todas aquellas páginas donde sea introducida información sensible, como datos personales o bancarios.
  • Evitar el secuestro de sesiones (session hijacking).
  • Evitar los ataques XSS (Cross Site Scripting).
  • Evitar los ataques XSRF (Cross Site Request Forgeries).
  • Mantener tus sistemas actualizados con los últimos parches disponibles.
  • Asegurarse de que la información de conexión a la base de datos está almacenada en un lugar lo suficientemente seguro.
  • Mantener informado sobre las últimas técnicas de ataque y vulnerabilidades que afecten a la plataforma sobre la que trabajas.
  • Conocer el manual The Google Browser Security Handbook.

Rendimiento

  • Implementar el cacheado de páginas cuando sea necesario. Comprender y usar apropiadamente los mecanismos de cacheo HTTP.
  • Optimizar las imágenes. Por ejemplo, no utilizar una imagen de 20 Kb. como mosaico de fondo.
  • Conocer cómo comprimir el contenido de las páginas con gzip.
  • Echar un vistazo al sitio Yahoo Exceptional Performance, donde se muestran directrices y buenas prácticas para mejorar el rendimiento de sitios web. Utilizar herramientas como YSlow.
  • Utilizar la técnica de CSS Sprites para las pequeñas imágenes (como las que encontramos en las barras de herramientas), con objeto de minimizar el número de peticiones HTTP.
  • Los sitios web de alto tráfico deberían considerar el despliegue de componentes en distintos dominios para optimizar la descarga en paralelo de los mismos.
  • En general, minimizar el número total de peticiones HTTP necesarias para que el navegador muestre las páginas.

SEO

  • Utilizar direcciones URL amigables para los buscadores. Por ejemplo, utilizar direcciones del tipo "ejemplo.com/paginas/titulo-del-articulo" en lugar de "ejemplo.com/index.php?page=45".
  • No utilizar enlaces que digan "pulse aquí". Estarías creando sitio web poco optimizado para buscadores, a la vez que complicando las cosas para los usuarios que utilizan lectores de pantalla.
  • Crear un mapa del sitio en XML (sitemap).
  • Utilizar <link rel="canonical" ... /> Cuando tengas múltiples URLs que apunten a un mismo contenido.
  • Utilizar las herramientas disponibles en www.google.com/webmasters.
  • Instalar Google Analytics desde el principio.
  • Conocer cómo funcionan los rastreadores de los buscadores y el archivo robots.txt.
  • No maquetar con tablas; Google generalmente valorará positivamente el marcado HTML semántico y la maquetación con CSS.
  • Si tienes contenido no textual en la página, utiliza en el sitemap las extensiones de Google para audio, video, etc. Hay alguna información sobre ello en la respuesta de Tim Farley.

Tecnología

  • Entender el protocolo HTTP; conocer cosas como GET, POST, sesiones, cookies, y saber lo que significa e implica su naturaleza "sin estado" (stateless).
  • Escribir el código (X)HTML y CSS conformes a las especificaciones de la W3C, y asegurarse de que validan. El objetivo es evitar las particularidades de los navegadores, a la vez que se facilita enormemente la navegación utilizando browsers no estándar como lectores de pantalla o dispositivos móviles.
  • Comprender cómo se procesa el código javascript en los navegadores. Mover los scripts al final de las páginas.
  • Comprender cómo funciona el sandbox de javascript, especialmente si pretendes utilizar iframes.
  • Asegurarse de que javascript puede ser deshabilitado sin que la página deje de funcionar. AJAX debe ser una extensión, y no la base sobre la que se construya un sitio. Aunque la mayoría de usuarios lo tengan activado, recordar que existen muchos y muy populares dispositivos en los que no funcionará correctamente.
  • Entender la diferencia entre las reflexiones 301 y 302 (esto también es un aspecto SEO).
  • Aprender tanto como sea posible sobre la plataforma en la que será desplegado el sitio web en producción.
  • Considerar el uso de un reseteador de CSS.
  • Considerar herramientas como jQuery, que oculta muchas de las particularidades de los distintos navegadores utilizando javascript para la manipulación del DOM.

Corrección de errores

  • Entender que pasarás el 20% del tiempo codificando y el 80% restante manteniéndolo, por tanto codifica apropiadamente.
  • Configurar un buen sistema de notificación y gestión de errores.
  • Habilitar sistemas para que los usuarios puedan contactar contigo y trasladarte críticas y sugerencias.
  • Documentar cómo funciona la aplicación para facilitar el futuro soporte y mantenimiento del sistema.
  • Poner a funcionar el sistema primero en Firefox y después en Internet Explorer.
  • Hacer copias de seguridad frecuentes.

Publicado en: Variable not found.