
Además de estar casi totalmente de acuerdo con los puntos expuestos en su post, que enumero y comento a continuación, añadiré algunos más de propia cosecha de agentes irritantes.
- 10. Comentarios que explican el "cómo" y no el "qué". Tan importante es incluir comentarios en el código como hacerlo bien. Es terrible encontrar comentarios que son una simple traducción literal al español del código fuente, pues no aportan información extra, en lugar de una explicación de lo que se pretende hacer. Muy bueno el ejemplo de Kevin en el post original... ¿eres capaz de decir qué hace este código, por muy comentado que esté?
r = n / 2; // Set r to n divided by 2
// Loop while r - (n/r) is greater than t
while ( abs( r - (n/r) ) > t ) {
r = 0.5 * ( r + (n/r) ); // Set r to half of r + (n/r)
} - 9. Las interrupciones. Sin duda, el trabajo de desarrollador requiere concentración y continuidad, y las interrupciones son las grandes enemigas de estos dos aspectos. Una jornada de trabajo llena de llamadas, mensajes o consultas de clientes, proveedores, jefes o compañeros puede resultar realmente frustrante, a la vez que la distracción que introduce suele ser una fuente importante de errores en las aplicaciones.
- 8. Ampliación del ámbito. Una auténtica pesadilla, sobre todo cuando se produce durante el desarrollo, consistente en el aumento desproporcionado del alcance de determinadas funcionalidades o características del software a crear. Es especialmente desmotivador si, además, no viene acompañado por el aumento del tiempo o recursos necesarios para su realización.
Kevin incluye en su artículo un ejemplo, algo exagerado pero ilustrativo, de sucesivas ampliaciones de ámbito que convierten un requisito factible en un infierno para el desarrollador; seguro que os recuerda algún caso que habéis sufrido en vuestras propias carnes:- Versión 1: Mostrar un mapa de localización
-- Bah, fácil, sólo tengo que crear una imagen; incluso puedo basarme en algún mapa existente que encuentre por ahí - Versión 2: Mostrar un mapa 3D de localización
-- Uff, esto ya no es lo que hablamos; tendré que currarme bastante más el diseño, y ya no será tan fácil partir de alguno existente... - Versión 3: Mostrar un mapa 3D de localización, por el que el usuario pueda desplazarse volando
-- ¡!
- Versión 1: Mostrar un mapa de localización
- 7. Gestores que no entienden de programación. Otro motivo común de irritación entre los desarrolladores es la incapacidad de gestores para comprender las particularidades de la industria del software en la que trabajan. Este desconocimiento genera problemas de todo tipo en una empresa y suponen un estrés terrible para el desarrollador.
- 6. Documentar nuestras aplicaciones. Lamentablemente, en nuestro trabajo no todo es desarrollar utilizando lenguajes y tecnologías que nos divierten mucho. Una vez terminado un producto es necesario crear guías, manuales y, en general, documentación destinada al usuario final que, admitámoslo, nos fastidia bastante escribir.
- 5. Aplicaciones sin documentación. A pesar de que entendamos y compartamos el punto anterior, también nos fastidia enormemente tener que trabajar con componentes o librerías partiendo de una documentación escasa o nula. Si lo habéis sufrido, entenderéis lo desesperante que resulta ir aprendiendo el significado de las funciones de un API usando el método de prueba y error.
- 4. Hardware. Especialmente los errores de hardware que el usuario percibe como un fallo de la aplicación son normalmente muy difíciles de detectar: fallos de red, discos, problemas en la memoria... por desgracia, hay un amplio abanico de opciones. Y lo peor es que por ser desarrolladores de software se nos presupone el dominio y control absoluto en asuntos hardware, lo que no siempre es así.
- 3. Imprecisiones. Aunque Kevin lo orienta al soporte al usuario, el concepto es igualmente molesto en fases de diseño y desarrollo del software. Las descripciones vagas y confusas son una causa segura de problemas, sea en el momento que sea.
Son irritantes las especificaciones imprecisas, del tipo "esta calculadora permitirá al usuario realizar sumas, restas, multiplicaciones y otras operaciones"... ¿qué operaciones? ¿divisiones? ¿resolver ecuaciones diferenciales?
Tampoco es fácil encajar un mensaje de un usuario tal que "me falla el ERP, arréglalo pronto"... A ver. El ERP tiene cientos de módulos, ¿fallan todos? ¿podríamos ser más concretos? - 2. Otros programadores. Como comenta Kevin, el malestar que provoca a veces la relación entre programadores bien merecería un post independiente, pero ha adelantado aspectos que, en su opinión, hace que a veces el trato con los compañeros sea insoportable:
- Personalidad gruñona, hostilidad
- Problemas para comprender que hay que dejar de debatir la arquitectura del sistema y pasar a realizar las tareas
- Falta de habilidad para mantener una comunicación efectiva
- Falta de empuje
- Apatía hacia el código y el proyecto
- 1. Tu propio código, 6 meses después. Sí, es frustrante estar delante de un código aberrante y darte cuenta de que tú eres el autor de semejante desastre. Y tras ello llega la fase de flagelación: ¿en qué estaba pensando cuando hice esto? ¿cómo fui tan estúpido? uff...
Este hecho, sin embargo, forma parte de la evolución tecnológica, personal y profesional; todos estos factores están en continuo cambio, lo que hace que nuestra forma de atacar los problemas sea distinta casi cada día.

- Extra 1. Requisitos evolutivos, como una ampliación del ámbito del punto 8 ;-), que son aquellos que van cambiando conforme el desarrollo avanza y que obligan a realizar refactorizaciones, descartar código escrito, e introducir peligrosas modificaciones, afectando a veces por debajo de la línea de flotación del software. Más rabia produce, además, cuando se atribuyen una mala interpretación por parte del desarrollador de una especificación imprecisa.
- Extra 2. Problemas en el entorno. Nada más frustrante que cortes en el suministro eléctrico, cuelgues, problemas en el hardware, lentitud en los equipos de trabajo o de acceso a información... a veces parece que tenemos que construir software luchando contra los elementos.
- Extra 3. El "experto" en desarrollo de software. Clientes, gestores y otros individuos que utilizan frecuentemente, y sin conocimiento alguno de causa, expresiones como "Esto es fácil", "Una cosa muy sencilla", "¿Eso vas a tardar en hacer esta tontería?".... A veces no es fácil hacer entender que la percepción externa de la complejidad es absolutamente irreal, y suele ser una causa frecuente de desesperación para los desarrolladores.
- Extra 4. Usuarios corrosivos, que lejos de colaborar durante el desarrollo o la implantación de un sistema, aprovechan la ocasión para arremeter contra la aplicación, organización, jefes, compañeros, el gobierno, o lo que se ponga por delante. Es de justicia decir que muchas veces este comportamiento es debido a una mala gestión interna del proyecto, pero desde el punto de vista del profesional del sofware que sólo quiere realizar lo mejor posible su trabajo son una auténtica pesadilla.
En fin, que ya a estas alturas es fácil ver que hay bastantes cosas que fastidian a los desarrolladores, y seguro que podríamos añadir muchas más; algunas son evitables, otras son inherentes a la profesión y hay que aprender a convivir con ellas, pero en cualquier caso son un interesante motivo de reflexión.
¿Y a tí, qué es lo que más te fastidia?
Enlace: Top 10 Things That Annoy Programmers
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:58 p. m.
Etiquetas: desarrollo, opinión, productividad, programación

Como sabemos, la propiedad
Master
de las páginas de contenidos, a través de la cual es posible acceder a la página maestra, es por defecto del tipo MasterPage
. Esto es así porque todas las masters que creamos heredan de esta clase, y es una abstracción bastante acertada la mayoría de las veces. De hecho, es perfectamente posible hacer un cast al tipo correcto desde el código de la página para acceder a alguna de las propiedades públicas que le hayamos definido, así:
protected void Page_Load(object sender, EventArgs e)
{
MaestraContenidos master = Master as MaestraContenidos;
master.Titulo = "Título";
}
Pues bien, mediante la directiva de página
MasterType
es posible indicar de qué tipo será esta propiedad Master, de forma que no será necesario hacer el cast. En la práctica, en el ejemplo anterior, podríamos hacer directamente Master.Titulo="Título"
, sin realizar la conversión previa.La directiva podemos utilizarla en el archivo .ASPX, haciendo referencia al archivo donde está definida la página maestra cuyo tipo usaremos para la propiedad:
<%@ MasterType VirtualPath="~/site1.master" %>
O también podemos hacerlo indicando directamente el tipo (ojo, que hay que incluirlo con su espacio de nombres completo):
<%@ MasterType TypeName="ProyectoWeb.MaestraContenidos" %>
Por último, algunas contraindicaciones. Si váis a usar esta técnica, tened en cuenta que:
- si decidís cambiar la página maestra en tiempo de ejecución, en cuanto intentéis acceder a la propiedad Master, vuestra aplicación reventará debido a que el tipo no es el correcto.
- si cambiáis la maestra a la que está asociada una página de contenidos, tenéis que acordaros de cambiar también la directiva
MasterType
de la misma para que todo funcione bien.
Publicado en: www.variablenotfound.com.

¡Gracias, Javi!
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:12 p. m.
Etiquetas: buscadores, curiosidades, google, humor, servicios on-line

Recapitulando, las técnicas de camuflaje de emails que habían aguantado el año y medio del experimento de Silvan Mühlemann, y por tanto se entendían más seguras que el resto de las empleadas en el mismo, fueron:
- Escribir la dirección al revés en el código fuente y cambiar desde CSS la dirección de presentación del texto.
- Introducir texto incorrecto en la dirección y ocultarlo después utilizando CSS.
- Generar el enlace desde javascript partiendo de una cadena codificada en ROT13.
En tiempo de ejecución, el control es capaz de generar código javascript que escribe en la página un enlace
mailto:
completo, partiendo de una cadena previamente codificada creada desde el servidor. Dado que todavía no está generalizado entre los spambots la ejecución de javascript de las páginas debido al tiempo y capacidad de proceso necesario para realizarlo, podríamos considerar que esta es la opción más segura.
Pero, ah, malditos posyaques... la verdad es que con un poco de refactorización era posible generalizar el procedimiento de codificación y decodificación mediante el uso de clases específicas (Codecs), así que me puse manos a la obra. Liame incluye, de serie, cuatro algoritmos distintos de ofuscación para ilustrar sus posibilidades: ROT-N (el usado por defecto y más recomendable), Base64, codificación hexadecimal, y un codec nulo, que me ha sido muy útil para depurar y usar como punto de partida en la creación de nuevas formas de camuflaje. Algunos, además, aleatorizan los de nombres de funciones y variables para hacer que el código generado sea ligeramente distinto cada vez, de forma que un spammer no pueda romperlo por una simple localización de cadenas en posiciones determinadas; en fin, puede que sea una técnica un poco inocente, pero supongo que cualquier detalle que dificulte aunque sea mínimamente la tarea de los rastreadores, bueno será.
Incluso si así lo deseamos podremos generar, además del javascript de decodificación del enlace, el contenido de la etiqueta
<noscript>
, en la que se incluirá el código HTML de la dirección a ocultar utilizando los dos trucos CSS descritos anteriormente y también considerados "seguros" por el experimento. De esta forma, aunque no estará disponible el enlace para este grupo de usuarios, podrán visualizar la dirección a la que podrán remitir sus mensajes.
Sin embargo, aún quedaba una cosa pendiente. El control de servidor está bien siempre usemos ASP.NET y que el rendimiento no sea un factor clave, puesto que al fin y al cabo estamos cargando de trabajo al servidor. Para el resto de los casos, Liame incluye en el proyecto de demostración un generador de javascript que, partiendo de los parámetros que le indiquemos, nos creará un script listo para copiar y pegar en nuestras páginas (X)HTML, PHP, Java, o lo que queramos. Como utiliza la base de Liame, cada script que generamos será distinto al anterior.
He publicado el proyecto en Google Code, desde donde se puede descargar tanto el ensamblado compilado como el código fuente del componente y del sitio de demostración. Esta vez he elegido la licencia BSD, no sé, por ir probando ;-)
La versión actual todavía tiene algunos detallitos por perfilar, como el control de la entrada en las propiedades (en especial las comillas y caracteres raros: ¡mejor que nos los uséis!), que podría dar lugar a un javascript sintácticamente incorrecto, pero en general creo que se trata de una versión muy estable. Ha sido probada con Internet Explorer 7, Firefox 3 y Chrome, los tres navegadores que tengo instalados.
También, por cortesía de Mergia, he colgado un proyecto de demostración para que pueda verse el funcionamiento en vivo y en directo, tanto del control de servidor como del generador de javascript.

Finalmente, algunos aspectos que creo interesante comentar. En primer lugar, me gustaría recordaros que las técnicas empleadas por Liame no aseguran, ni mucho menos, que los emails de las páginas van a estar a salvo de los del lado oscuro eternamente, aunque de momento así sea. Lo mejor es no confiarse.
En segundo lugar, es importante tener claro que todas las técnicas aquí descritas pueden resultar bastante nocivas para la accesibilidad de las páginas en las que las utilicéis. Tenedlo en cuenta, sobre todo, si tenéis requisitos estrictos en este sentido.
Y por último, añadir que estaré encantado de recibir vuestras aportaciones, sugerencias, colaboraciones o comentarios de cualquier tipo (sin insultar, eh?) que puedan ayudar a mejorar este software.
Enlaces
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:56 p. m.
Etiquetas: asp.net, componentes, herramientas, liame, scripting, software libre, utilidades

Esto se traduce, en primer lugar, en que será distribuida con Visual Studio, pero eso sí, tal cual, sin modificaciones ni aditivos que puedan suponer la separación de las versiones oficiales de jQuery. Por ejemplo, ASP.NET MVC incluirá de serie la librería en las plantillas de los nuevos proyectos.
Pero no acaban ahí los compromisos. También facilitarán versiones con anotaciones que permitirán disfrutar totalmente de la experiencia intellisense mientras trabajemos con ella, que según comentan estará disponible como una descarga gratuita independiente en unas semanas. Incluso el soporte 24x7 para desarrolladores podrán abrir cuestiones relacionadas con esta librería.
Asimismo, se pretende darle uso para la implementación de controles para el ASP.NET AJAX Control Toolkit, para la construcción de helpers para el framework MVC, y, en general, integrarla con todas las nuevas características y desarrollos que vayan apareciendo.
Buena noticia, sin duda... :-)
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 9:30 p. m.
Etiquetas: desarrollo, herramientas, jquery, microsoft

Las demostraciones de este motor son ejecutables, por lo que hay que descargarlas y ejecutarlas en el equipo local. Si utilizáis Windows, os recomiendo echar un vistazo al paquete de demostraciones [~3MB], con el que se puede comprobar la potencia de la librería. No es necesario instalar nada, sólo descomprimir el contenido en una carpeta y ejecutar la demo.
La revisión actual, 2.71 se publicó hace tan sólo unos días. El código fuente del proyecto está alojado en Google Code, y su modelo de licencia (MIT) permite su utilización en proyectos comerciales.
Y por cierto, existe un port para Java, jBullet, cuyas demostraciones pueden descargarse y ejecutarse a través de Java Webstart, por lo que resulta mucho más cómodo. Incluso aunque el rendimiento es muy inferior al real al usar renderizado por software, puede ejecutarse en un applet, que incrusto a continuación.
Debéis elegir una demo en el desplegable (hay cinco disponibles, os recomiendo que comencéis por la primera), en las que podéis usar las teclas "Z" y "X" para acercaros y alejaros de la escena, las flechas de dirección para girar, y con el ratón podéis aplicar impulsos a los cubos (arrastrando con el botón izquierdo) y lanzar cubos (con el bótón derecho).
Como observaréis, dentro del mismo applet aparecen instrucciones de otras teclas, incluso algunas para demos concretas. Especialmente interesante e improductivo es lanzarle piezas al cubo gigante (basic demo), intentar hacer caminar la araña (dynamic control demo), o dedicarse a transportar mesas de un lado a otro con una carretilla (forklift demo).
Que lo disfrutéis.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 9:20 p. m.
Etiquetas: curiosidades, motores de física, programación

Lo que no conocía era la posibilidad de establecerlos por código desde la propia aplicación que estamos depurando, que puede resultar útil en momentos en que nos sea incómodo crearlos desde el entorno de desarrollo. Es tan sencillo como incluir el siguiente fragmento en el punto donde deseemos que la ejecución de detenga y salte el entorno:
// C#
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
}
' VB.NET:
If System.Diagnostics.Debugger.IsAttached Then
System.Diagnostics.Debugger.Break()
End If
Como ya habréis adivinado, el
if
lo único que hace es asegurar que la aplicación se esté ejecutando enlazada a un depurador, o lo que es lo mismo, desde dentro del entorno de desarrollo; si se ejecuta fuera del IDE no ocurrirá nada.Si eliminamos esta protección, la llamada a
Debugger.Break()
desde fuera del entorno generará un cuadro de diálogo que dará la oportunidad al usuario de abrir el depurador:
De todas formas lo mejor es usarlo con precaución, que eso de dejar el código con residuos de la depuración no parece muy elegante...
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:37 p. m.
Etiquetas: depuración, desarrollo, programación, trucos

El genial Kevin Pang ha publicado un divertido artículo en Datamation, Debugging and The Five Stages of Grief, utilizándolas para describir los sentimientos del desarrollador ante la aparición de un bug en su aplicación:
- Negación. En esta fase, ante el descubrimiento de un posible fallo, nos ponemos en actitud defensiva e intentamos echarle la culpa a todo menos a nuestros desarrollos. Nosotros no fallamos nunca... ¿o tal vez sí?
- Ira. Acto seguido, una vez demostrado que existe un problema, comienzan los bufidos, resoplidos y voces airadas del tipo ¿cómo no se ha detectado esto antes?, ¡vaya mierda de aplicación!, o ¡¡joder, justo ahora, con lo ocupado que estoy!!
- Negociación. Vale, asumimos que hay un error y ya hemos despotricado durante un rato. El siguiente paso es negociar (habitualmente con nosotros mismos) sobre el tipo de solución a dar: ¿apuntalamos lo suficiente como para que siga funcionando, u optamos por solucionar de forma definitiva el problema? Difícil decisión a veces.
- Depresión. Ahora lo que toca es la depresiva tarea de la depuración. A nadie le gusta escudriñar en el código en busca de un error, ¡hemos nacido para crear software espectacular, no para corregirlo! Es un buen momento para compadecernos de nosotros mismos.
- Aceptación. Hemos asimilado la realidad de que nuestro código falla, hemos maldecido la situación, decidido que vamos a corregirlo como auténticos profesionales, e incluso hemos llorado un rato sobre nuestra mala suerte. Sin embargo, esto es así y hay que aceptarlo, forma parte de la pesada mochila que los desarrolladores llevamos a las espaldas. Eso sí, sólo otro desarrollador puede entenderlo, no intentes explicárselo a tu esposa, madre, jefe, o vecino.
Si tienes un rato, no te pierdas el artículo original.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:18 p. m.
Etiquetas: curiosidades, desarrollo, humor, programación

Se trata de la polilla que provocó problemas de funcionamento en el primitivo ordenador Mark II el martes 9 de septiembre de 1947, al colarse y quedarse atrapada en el relé número 70 del Panel F (que debe venir a ser algo así como la línea X del archivo Y del código fuente de los de ahora). La incidencia fue reflejada en el cuaderno de bitácora (log) del sistema, al que pertenece la fotografía superior, adjuntando el insecto como prueba del delito.
El término "bug" ya se utilizaba entonces como sinónimo de error en otros ámbitos, como en telegrafía, telefonía o sistemas eléctricos, de ahí la frase que registró el operador debajo del animalito, haciendo referencia a que era la primera vez que se encontraba un auténtico bug (=bicho):
"First actual case of bug being found"
Fuente: The first computer bug
Publicado en: www.variablenotfound.com.

Esta técnica es tan antigua como la Web, y por este motivo (y no por otros ;-)) estamos en las listas de vendedores de viagra y alargadores de miembros todos aquellos que aún conservamos buzones desde los tiempos en que Internet era un lugar cándido y apacible. Años atrás, poner tu email real en una web, foro o tablón era lo más normal y seguro.
Pero los tiempos han cambiado. Hoy en día, publicar la dirección de email en una web es condenarla a sufrir la maldición del spam diario, y sin embargo, sigue siendo un dato a incluir en cualquier sitio donde se desee facilitar el contacto vía correo electrónico tradicional. Y justo por esa razón existen las técnicas de ofuscación: permiten, o al menos intentan, que las direcciones email sean visibles y accesibles para los usuarios de un sitio web, y al mismo tiempo sean indetectables para los robots, utilizando para ello diversas técnicas de camuflaje en el código fuente de las páginas.
Desafortunadamente, ninguna técnica de ofuscación es perfecta. Algunas usan javascript, lo cual impide su uso en aquellos usuarios que navegan sin esta capacidad (hay estadísticas que estiman que son sobre el 5%); otras presentan problemas de accesibilidad, compatibilidad con algunos navegadores o impiden ciertas funcionalidades, como que el sistema abra el cliente de correo predeterminado al pulsar sobre el enlace; otras, simplemente, son esquivables por los spammers de forma muy sencilla.
En el fondo se trata de un problema similar al que encontramos en la tradicional guerra virus vs. antivirus: cada medida de protección viene seguida de una acción en sentido contrario por parte de los spammers. Una auténtica carrera, vaya, que por la pinta que tiene va a durar bastante tiempo.
En 2006, Silvan Mühlemann comenzó un interesante experimento. Creó una página Web en la que introdujo nueve direcciones de correo distintas, y cada una utilizando un sistema de ofuscación diferente:
- Texto plano, es decir, introduciendo un enlace del tipo:
<a href="mailto:user@myserver.xx">email me</a>
- Sustituyendo las arrobas por "AT" y los puntos por "DOT", de forma que una dirección queda de la forma:
<a href="mailto:userATserverDOTxx">email me</a>
- Sustituyendo las arrobas y puntos por sus correspondientes entidades HTML:
<a href="mailto:user@server.xx">email me</a>
- Introduciendo la dirección con los códigos de los caracteres que la componen:
<a href="mailto:%73%69%6c%76%61%6e%66%6f%6f%62%61%72%34%40%74%69%6c%6c%6c%61%74%65%65%65%65%65">email me</a>
- Mostrando la dirección de correo sin enlace y troceándola con comentarios HTML, que el usuario podrá ver sin problema como user@myserver.com aunque los bots se encontrarán con algo como:
user<!-- -->@<!--- @ -->my<!-- -->server.<!--- . -->com
- Construyendo el enlace desde javascript en tiempo de ejecución con un código como el siguiente:
var string1 = "user";
var string2 = "@";
var string3 = "myserver.xx";
var string4 = string1 + string2 + string3;
document.write("<a href=" + "mail" + "to:" + string1 +
string2 + string3 + ">" + string4 + "</a>"); - Escribiendo la dirección al revés en el código fuente y cambiando desde CSS la dirección de presentación del texto, así:
<style type="text/css">
span.codedirection { unicode-bidi:bidi-override; direction: rtl; }
</style>
<span class="codedirection">moc.revresym@resu</span> - Introduciendo texto incorrecto en la dirección y ocultándolo después desde CSS:
<style type="text/css">
span.displaynone { display:none; }
</style>
Email me: user@<span class="displaynone">goaway</span>myserver.net - Generando el enlace desde javascript partiendo de una cadena codificada en ROT13, según una idea original de Christoph Burgdorfer:
<script type="text/javascript">
document.write('<n uers=\"znvygb:fvyinasbbone10@gvyyyngr.pbz\" ery=\"absbyybj\">'.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c<="Z"?90:122)>=(cc=c.charCodeAt(0)+13)?c:c-26);}));
</script>silvanfoobar's Mail</a>

Por tanto, atendiendo al resultado de este experimento, si estamos desarrollando una página que asume la existencia de javascript podríamos utilizar el método del ROT13 (9) para generar los enlaces
mailto:
con ciertas garantías de éxito frente al spam. Podéis usar el código anterior, cambiando el texto codificado (en negrita) por el que generéis desde esta herramienta (ojo: hay que codificar la etiqueta de apertura completa, como <a href="mailto:loquesea">
, incluidos los caracteres de inicio "<" y fin ">", pero sin introducir el texto del enlace ni el cierre </a>
de la misma).También podemos utilizar alternativas realmente ofuscadoras, como la ofrecida por el Enkoder de Hivelogic, una herramienta on-line que nos permite generar código javascript listo para copiar y pegar, cuya ejecución nos proporcionará un enlace
mailto:
completo en nuestras páginas.Pero atención, que el uso de javascript no asegura el camuflaje total y de por vida de la dirección de correo por muy codificada que esté en el interior del código fuente. Un robot que incluya un intérprete de este lenguaje y sea capaz de ejecutarlo podría obtener el email finalmente mostrado, aunque esta opción, por su complejidad y coste de proceso, no es todavía muy utilizada; sí que es cierto que algunos recolectores realizan un análisis del código javascript para detectar determinadas técnicas, por lo que cuando más ofuscada y personalizada sea la generación, mucho mejor.
En caso contrario, si no podemos usar javascript, lo tenemos algo más complicado. Con cualquiera de las soluciones CSS descritas en los puntos 7 y 8 (ambas han conseguido aguantar el tiempo del experimento sin recibir ningún spam), incluso una combinación de ambas, es cierto que el usuario de la página podrá leer la dirección de correo, mientras que para los robots será un texto incomprensible. Sin embargo, estaremos eliminando la posibilidad de que se abra el gestor de correo del usuario al cliquear sobre el enlace, así como añadiendo un importante problema de accesibilidad en la página. Por ejemplo, si el usuario decide copiar la dirección para pegarla en la casilla de destinatario de su cliente, se llevará la sorpresa de que estará al revés o contendrá caracteres extraños. Por tanto, aunque pueda ser útil en un momento dado, no es una solución demasiado buena.
La introducción de "AT" y "DOT", o equivalentes en nuestro idioma como "EN" y "PUNTO", con adornos como corchetes, llaves o paréntesis podrían prestar una protección razonable, pero son un incordio para el usuario y una aberración desde el punto de vista de la accesibilidad. Además, el hecho de que se haya recibido algún mensaje en el buzón que utilizaba esta técnica ya implica que hay spambots que la contemplan y, por tanto, en poco tiempo podría estar bastante popularizada, por lo que habría que buscar combinaciones surrealistas, más difíciles de detectar, como "juanARROBICAservidorPUNTICOcom", o "juanCAMBIA_ESTO_POR_UNA_ARROBAservidorPON_AQUI_UN_PUNTOcom". Pero lo dicho, una incomodidad para el usuario en cualquier caso.
Hay otras técnicas que pueden resultar también válidas, como introducir las direcciones en imágenes, applets java u objetos flash incrustados, redirecciones y manipulaciones desde servidor, el uso de captchas, y un largo etcétera que de hecho se usan en multitud de sitios web, pero siempre nos encontramos con problemas similares: requiere disponer de algún software (como flash, o una JVM), una característica activa (por ejemplo scripts o CSS), o atentan contra la usabilidad y accesibilidad del sitio web.
Como comentaba al principio, ninguna técnica es perfecta ni válida eternamente, por lo que queda al criterio de cada uno elegir la más apropiada en función del contexto del sitio web, del tipo de usuario potencial y de las tecnologías aplicables en cada caso.
La mejor protección es, sin duda, evitar la inclusión de una direcciones de email en páginas que puedan ser accedidas por los rastreadores de los spammers. El uso de formularios de contacto, convenientemente protegidos por sistemas de captcha gráficos (¡los odio!) o similares, pueden ser un buen sustituto para facilitar la comunicación entre partes sin publicar direcciones de correo electrónico.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 9:52 p. m.
Etiquetas: css, javascript, ofuscación de emails, scripting, spam, web, xhtml

Muchas son las novedades que han introducido esta vez, y algunas realmente muy esperadas, como el sistema de validaciones de datos en formularios, nuevos atributos de nombrado y filtrado de acciones, o los ModelBinders, el mecanismo que permite utilizar parámetros de tipos complejos (es decir, no nativos) en las acciones de nuestros controladores. Richard Chamorro ha realizado un buen resumen de las novedades y cambios de esta entrega respecto a la preview 4, en las que ya iremos profundizando.
Y a propósito de la Preview 4, también introdujo bastantes novedades respecto a la anterior: nuevos atributos de filtros de ejecución de acciones y captura de errores de ejecución, control sobre el cacheado de respuestas, algunos helpers básicos destinados al intercambio de datos usando Microsoft Ajax, cambios en las plantillas para Visual Studio introduciendo controladores y vistas para un sistema simple de autenticación de usuarios y gestión de errores, y otras mejoras. Sin embargo, debido al cierre por vacaciones de Variable not found y a la aparición de la preview 5 no he tenido tiempo para ir revisándolas; ya iré comentando los que me resulten especialmente interesantes.
Por último, según indica el gran Phil Haack en su post "ASP.NET MVC Codeplex preview 5 released", no entra en sus planes que haya más previews. Lo próximo que tendremos entre las manos será ya una versión Beta, muy cercana al producto final que podremos disfrutar sobre finales de año ("en un mes que acabe en -bre", como bromeó hace poco Scott Hanselman). Eso sí, supongo que antes pasaremos por varias betas e incluso alguna versión candidata.
Parece que tenemos unos meses divertidos por delante...
Publicado en: www.variablenotfound.com.

Para lograrlo, necesitamos solucionar dos problemas. El primero es cómo indicar en los enlaces (dentro de la etiqueta
<a>
de nuestro código X/HTML) el idioma de la página a la que saltará el usuario; el segundo problema es el describir en la hoja de estilos (CSS) estos enlaces, de forma que se representen con la banderita correspondiente. Ambos tienen fácil solución gracias a los estándares de la W3C.Hace ya bastantes años, el estándar HTML definió el atributo
hreflang
en los hipervínculos con objeto de indicar el idioma del recurso apuntado por el atributo href
. En otras palabras, si estamos apuntando a una página debería contener el idioma de la misma, justo lo que necesitamos: <a href="http://www.csszengarden.com" hreflang="en">CSS Zen Garden</a>
Por otra parte, el estándar CSS 2.1 define un gran número de selectores que podemos utilizar para identificar los elementos de nuestra página a los que queremos aplicar las reglas de estilo especificadas. El que nos interesa para lograr nuestro objetivo es el llamado selector de atributos, que aplicado a una etiqueta permite filtrar los elementos que presenten un valor concreto asociado a un atributo de la misma.
Así, en el siguiente código, que debemos incluir en la hoja de estilos del sitio web, buscamos los enlaces cuya página de destino sea en inglés (su
hreflag
comience por "en"), introduciendo el efecto deseado:a[hreflang="en"]
{
padding-right: 19px;
background-image: url(img/bandera_ing.jpg);
background-position: right center;
background-repeat: no-repeat;
}
Observad que el
padding-right
deja un espacio a la derecha del enlace con la anchura suficiente como para que se pueda ver la imagen de fondo, la banderilla, que aparecerá allí gracias a su alineación horizontal a la derecha definida con el background-position
.Y, ahora sí, podemos recomendar visitas a páginas en inglés como CSS Zen Garden con fundamento.
Ah, un último detalle. Aunque hoy en día los navegadores tienden cada vez más a respetar los estándares, es posible que encontréis alguno con el que no funcione bien esta técnica principalmente por no soportar el selector de atributos (por ejemplo IE6 y anteriores, afortunadamente cada vez menos usados).
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 10:25 p. m.
Etiquetas: css, desarrollo, estándares, trucos, web, xhtml

Pero, como siempre, todo lo bueno se acaba y aquí estamos de nuevo, sin indicios de síndrome postvacacional, con las pilas bien cargadas y listos para iniciar una nueva temporada en Variable Not Found, donde espero contar, como hasta ahora, con vuestra participación y apoyo.
Gracias por seguir por aquí. Nos vemos pronto.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 12:15 a. m.
Etiquetas: blogging, historias, personal, vacaciones

Pero reponerse es fácil si se tienen buenos planes para este mes de Agosto, como es el caso. Comenzaremos con unos días en Sanlúcar de Barrameda, localidad que ya nos fascinó cuando la conocimos el año pasado.
También vamos a poder disfrutar de un viaje familiar al paraíso canario, y más concretamente al Puerto de la Cruz, en Tenerife, donde esperamos pasárnoslo en grande.
Y entre una cosa y otra, paraditas en casa para descansar, y quizás alguna visita a playas de Huelva. No nos podemos quejar, desde luego.
Variable not found, como siempre por esta fecha, quedará a la deriva hasta primeros de Septiembre, momento en el que volveré a retomarlo todo con la energía convenientemente renovada.
Ah, voy a desactivar temporalmente los comentarios anónimos, para evitar que los spammers se ceben con el blog. Siento las molestias que pueda causar a los que sólo quieren dejar sus impresiones o cuestiones anotadas por aquí.
Feliz verano, amigos.
Publicado en: www.variablenotfound.com.

Benicio Romero Santacruz
Padre Caro, 61
13592 Mestanza
Email Address: BenicioRomeroSantacruz@fontdrift.com
This is a real email address. Click here to use it!
Website: Demimba.com
It looks like Demimba.com is available! Click here to register it!
Birthday: June 17, 1980
Visa: 4929 7908 0245 3619
Expires: 6/2011
UPS Tracking Number: 1Z F00 647 14 8092 598 8
Como podéis ver, incluye un nombre, la dirección una cuenta de correo (tipo Mailinator) que podéis usar para recibir mensajes simplemente pulsando el enlace mostrado, fecha de nacimiento, datos de una tarjeta VISA (no válidos, claro), y un código de seguimiento de UPS.
Puedes generar tu identidad española siguiendo este enlace.
En fin, que no es algo especialmente útil, pero curioso lo es un rato...
Publicado en: http://www.variablenotfound.com/.

Ya comenté en otra ocasión los distintos subtipos de
ActionResult
incluidos en el framework, y la posibilidad de crear nuevos descendientes. También tratamos en otro post el retorno de JSON desde los controladores como una potente vía de devolución de datos estructurados a la capa cliente, tras una llamada Ajax.En esta ocasión vamos a profundizar un poco más, creando nuestro propia subclase de
ActionResult
para crear acciones con resultados personalizados utilizando la Preview 3 de esta tecnología. Concretamente, crearemos la clase ImageResult
, que permitirá a las acciones retornar imágenes JPEG como la mostrada en la siguiente captura:
Como se puede observar, aparece una imagen con la hora actual sobre un fondo degradado, que es generada en tiempo real desde el servidor al producirse una petición desde la vista mediante un tag <img> estándar:
<h3>La hora es:</h3>
<img src='<%= Url.Action("GetImage") %>' />
La llamada al método
Url.Action("GetImage")
retorna una cadena con la dirección URL de la acción indicada en el parámetro, en este caso GetImage()
. De esta forma, cuando el navegador necesite cargar la imagen para mostrarla, realizará una llamada a dicha acción, cuyo código aparece en el controlador de la siguiente forma: public ImageResult GetImage()
{
return new ImageResult
{
Width = 400,
Height = 100,
Text = DateTime.Now.ToLongTimeString()
};
}
Lo único que hace es retornar un objeto
ImageResult
inicializado con el ancho y alto deseado, y el texto a escribir. Fijaos en el uso del inicializador de objetos.Veamos por último con la clase
ImageResult
: public class ImageResult: ViewResult
{
public int Width { get; set; }
public int Height { get; set; }
public string Text { get; set; }
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = "image/jpeg";
Rectangle rect = new Rectangle(0, 0, Width, Height);
Bitmap bmp = new Bitmap(rect.Width, rect.Height);
Graphics g = Graphics.FromImage(bmp);
Font font = new Font("Arial", Height / 1.6f);
LinearGradientBrush brush =
new LinearGradientBrush(rect, Color.Blue, Color.Navy, 90f);
g.FillRectangle(brush, rect); // Pinta el degradado...
g.DrawString(Text, font, Brushes.Black, 2, 2); // ... la sombra del texto...
g.DrawString(Text, font, Brushes.White, 0, 0); // ... y el texto.
g.Dispose();
font.Dispose();
brush.Dispose();
bmp.Save(context.HttpContext.Response.OutputStream, ImageFormat.Jpeg);
bmp.Dispose();
}
}
Aparte de la definición de las propiedades necesarias para su funcionamiento, el único truco a la hora de devolver contenidos personalizados es sobrescribir el método
ExecuteResult
de la clase base ViewResult
. Ya en su implementación, a través del contexto que nos llega como parámetro podemos modificar el tipo de contenidos de la respuesta (Content-Type) y escribir a través del canal de salida lo que deseemos (en este caso utilizamos el método Save
del bitmap para ello).El resto del código no tiene demasiado interés, es la creación de la imagen dinámica utilizando GDI+. Por cierto, no he realizado validaciones de las propiedades, os los dejo de deberes ;-); Tampoco sé si tantos Dispose() explícitos serán necesarios, supongo que no, pero me da algo de repelús no ponerlos... debe ser algo así como un trauma infantil adquirido años atrás usando el API de Windows...

Publicado en: www.variablenotfound.com.

En dicho post se mostraba la forma en que era posible intercambiar información estructurada con Ajax, definiendo en el servidor una clase propia y viendo cómo el ScriptManager, mágicamente, creaba un proxy (o espejo) en cliente que permitía su manipulación de forma muy cómoda y transparente al otro lado de la red.
De hecho, partíamos de una definición en el servidor así:
public class Mensaje
{
public string Remitente;
public string Destinatario;
public DateTime Fecha;
public int Numero;
}
Y veíamos como desde cliente podíamos manipularla, en javascript, de la siguiente forma:
msg = new Mensaje();
msg.Remitente = $get("nombre").value;
msg.Numero = 1;
msg.Destinatario = "servidor";
msg.Fecha = new Date();
El problema que comentaba este lector es que, a diferencia del ejemplo, su entidad de datos se encontraba definida en un ensamblado y espacio de nombres diferente al del WebMethod que lo utilizaba, lo que provocaba la aparición de un error indicando que su clase no estaba definida.
Aunque al principio sospeché en que podía existir alguna limitación en la seriación JSON de los datos, después de indagar un poco dí con la solución. La lección que he aprendido es:
para usar desde cliente una clase generada de forma automática por el ScriptManager, es necesario referenciarla precedida del namespace en el que se encuentra definidaO en otras palabras, si la clase
Mensaje
está definida dentro del espacio de nombres A.B
, la referencia en cliente deberá ser: var x = new A.B.Mensaje();
¿Y por qué funciona bien el ejemplo AjaxPingPong, si la referencia a la clase Mensaje
no incluía su espacio de nombres? Pues debido a que estaba definida en el namespace por defecto del proyecto...¡Gracias, Pedro, por participar en Variable Not Found!
Publicado en: www.variablenotfound.com.
Se trata de un proyecto personal de Dan Hounshell que recopila de forma automática posts, noticias, rumores y vídeos de feeds RSS de diversas fuentes sobre ASP.NET MVC y tecnologías relacionadas. Ah, y todos estos contenidos los ofrece en RSS, por lo que es una fuente ideal para estar al día.
Que aproveche.
Publicado en: www.variablenotfound.com.

debug=true
en el Web.config de servidores en producción debido a la sobrecarga que implica que la compilación de las páginas se realice con el modo de depuración activo.El problema es, primero, que hay que acordarse de cambiarlo antes de subir el sitio al servidor de producción y, segundo, que a los despistados nos suele ocurrir que tras subir una nueva versión de la aplicación podemos volver a dejarlo como estaba de forma involuntaria.
Supongo que habrá otras formas para controlarlo, pero hoy me he encontrado con una muy sencilla que nos permite averiguar en tiempo de ejecución si el sitio web está funcionando con la depuración activa o no:
IsDebuggingEnabled
, una propiedad de la clase HttpContext
.Así, podemos introducir un código como el siguiente en el Global.asax, que provocará la parada de la aplicación cuando intentemos iniciarla, desde un equipo remoto, si la directiva debug está establecida a true en el archivo de configuración.
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
if (HttpContext.Current.IsDebuggingEnabled
&& !HttpContext.Current.Request.IsLocal)
{
throw new Exception("¡Depuración habilitada!");
}
}
}
Otro ejemplo menos violento podría ser la inclusión de un mensaje de alerta en el pie todas las páginas mostradas cuando se estén ejecutando en modo depuración, para lo que habría que escribir el siguiente método en la clase
Global
del Global.asax:protected void Application_EndRequest(object sender, EventArgs e)
{
if (HttpContext.Current.IsDebuggingEnabled)
HttpContext.Current.Response.Write(
"<div style='background: red; color: white'>Sitio en depuración</div>"
);
}
Pero ojo, que esta propiedad sólo detecta el valor presente en el Web.config, no tiene en cuenta si a una página se le ha establecido Debug=true en sus directivas @Page, o si los ensamblados usados se compilaron en modo release o depuración.
Publicado en: www.variablenotfound.com.

En pocas palabras, consiste en llenar una lista desplegable con elementos elegidos en función de una decisión previa, como la selección en otra lista. El ejemplo típico lo encontramos en aplicaciones donde debemos introducir una dirección y nos ponen por delante un desplegable con las provincias y otro con los municipios, y en éste último sólo aparecen aquellos que pertenecen a la provincia seleccionada.
Esto, que en aplicaciones de escritorio no tiene dificultad alguna, en el entorno Web se complica un poco debido a la falta de comunicación entre la capa cliente (HTML, javascript) y servidor (ASP, .NET, JSP, PHP...), propia de un protocolo desconectado como HTTP.
Años atrás (e incluso todavía hoy) una forma de solucionar el problema es forzando un postback, es decir, una recarga de la página completa, con objeto de llenar el desplegable dependiente en función del valor seleccionado en el principal. Supongo que no es necesario detallar los inconvenientes: tiempos de espera, asombro del usuario ante el pantallazo, problemas asociados al mantenimiento del estado...
La aparición de Ajax (¡en minúsculas!) supuso una revolución para las aplicaciones Web, añadiendo a las amplias capacidades de Javascript para la manipulación del interfaz e información en cliente mecanismos ágiles para conseguir comunicación en tiempo real con el lado del servidor.
En este post explicaré cómo conseguir desplegables en cascada utilizando la plataforma ASP.NET MVC (Preview 3) en el lado servidor y Javascript en el lado cliente, apoyándome en la librería jQuery, que tanto juego da. Aprovecharé de paso para comentar algunos aspectos interesantes de la preview 3 del framework MVC, de jQuery y de novedades de C# 3.0. Tocho de post, por tanto ;-)
El resultado será un formulario como el mostrado en la siguiente imagen:

Antes de nada: estructurar la solución
Para lograr el objetivo pretendido respetando el patrón MVC, debemos contar con los siguientes elementos:- El modelo, que representará la información manejada por el sistema. Para no complicar el ejemplo (o complicarlo, según se mire ;-)), vamos a crear una colección en memoria sobre la que realizaremos las consultas.
- La vista, que será un formulario en el que colocaremos los dos desplegables. El primero de ellos permitirá seleccionar una categoría tomada del Modelo, y el segundo mostrará los elementos de dicha categoría de forma dinámica.
- El controlador, en el que incluiremos acciones, en primer lugar, para inicializar y mostrar el formulario y, en segundo lugar, para obtener la lista de elementos relacionados con la categoría seleccionada. Esta última acción será invocada por la vista cuando el primer desplegable cambie de valor.
Primero: el modelo
En escenarios reales será el conjunto de entidades que representen el modelo de datos del sistema. En este caso montaremos un ejemplo muy simple, basado en un diccionario en memoria, y un par de métodos de consulta de la información en él mantenida.public class Datos
{
private static Dictionary<string, string[]> datos =
new Dictionary<string, string[]>
{
{ "Animal", new[] { "Perro", "Gato", "Pez"} },
{ "Vegetal", new[] { "Flor", "Árbol", "Espárrago"} },
{ "Mineral", new[] { "Cuarzo", "Pirita", "Feldespato"} }
};
public static IEnumerable<string> GetCategories()
{
return datos.Keys;
}
public static IEnumerable<string> GetElementsForCategory(string category)
{
string[] els = null;
datos.TryGetValue(category, out els);
return els;
}
}
Destacar del código anterior los siguientes aspectos:
- La información se almacenará en un
Dictionary<string,string[]>
. Esto, por si no estás muy familiarizado con los generics o tipos genéricos, sólo quiere decir que se trata de un diccionario cuya clave será de tipo string (las categorías) y el valor será un array de strings (los elementos asociados a cada categoría).
De esta forma, podremos obtener fácilmente la lista de categorías simplemente enumerando las claves (Keys) del diccionario, y los elementos contenidos en una categoría sólo con devolver el valor asociado a la misma, como vemos en los métodosGetCategories()
yGetElementsForCategories()
. - Para inicializar el diccionario he utilizado un inicializador de colecciones, una característica de C# 3.0 ya comentada en un post anterior.
- Los dos métodos de consulta de datos retornan un
IEnumerable<string>
(¡me encantan los generics!), flexibilizando el tipo devuelto. Así, podríamos devolver cualquier tipo de objeto que implemente este interfaz, prácticamente todas las listas, colecciones y arrays, siempre que contengan en su interior unstring
.
Segundo: la vista
Para nuestro ejemplo sólo necesitamos una vista, el formulario con los desplegables, que crearemos en el archivo Index.aspx. Además de componer el interfaz, la vista gestionará la interacción con el usuario haciendo que ante la selección de una opción del desplegable de categorías se invoque al controlador para solicitarle la lista de elementos de la categoría seleccionada, y cargar con ella el segundo desplegable.El código fuente del proyecto completo lo podéis encontrar en un enlace al pie del post, pero incluiré aquí las porciones más importantes. En primer lugar, el formulario HTML se compone así:
<form method="post" action="#">
<fieldset><legend>Formulario</legend>
<label for="ddCategory">Categoría:</label>
<%= Html.DropDownList("ddCategory") %>
<label for="ddElement">Elemento:</label>
<%= Html.DropDownList("ddElement") %>
</fieldset>
</form>
Fijaos un momento en el código. Los desplegables, en lugar de utilizar el tag HTML <select> se han definido utilizando los métodos de ayuda (Html helpers) incluidos en el framework MVC. Estos, además de generar las etiquetas apropiadas, realizan otra serie de tareas como establecer valores de la lista, que nos ahorrarán mucho tiempo. En el controlador veremos cómo se le inyectan los elementos (los distintos <option>) desde código de forma muy sencilla.

<script type="text/javascript">
// Inicialización
$(document).ready(function() {
$("#ddCategory").change(function() {
cambiaElementos($("#ddCategory").val());
});
cambiaElementos($("#ddCategory").val());
});
// Carga el desplegable de elementos en función
// de la categoría que le llega como parámetro.
function cambiaElementos(cat) {
var dd = document.getElementById("ddElement");
dd.options.length = 0;
dd.options[0] = new Option("Espere...");
dd.selectedIndex = 0;
dd.disabled = true;
// Control de errores
$("#ddElement").ajaxError(function(event, request, settings) {
dd.options[0] = new Option("Categoría incorrecta");
});
// Obtenemos los datos...
$.getJSON(
'<%= Url.Action("GetElements") %>', // URL a la acción
{ category: cat }, // Objeto JSON con parámetros
function(data) { // Función de retorno exitoso
$.each(data, function(i, item) {
dd.options[i] = new Option(item, item);
});
dd.disabled = false;
});
}
</script>
En la primera parte se utiliza el evento jQuery
ready
, ejecutada cuando la página está lista para ser manipulada, para introducir código de inicialización. En este momento se asocia al evento change
del desplegable de categorías la llamada apropiada a la función cambiaElementos()
, pasándole la categoría seleccionada. También se aprovecha para realizar la primera carga de elementos.
cambiaElementos
, que se encargará de actualizar el desplegable con los elementos asociados a la categoría seleccionada. Para ello, en primer lugar, se introduce en el dropdown un elemento con el texto "Espere...", que aparecerá mientras el sistema obtiene los datos desde el servidor, a la vez que se deshabilita el control para evitar manipulación del usuario.Después se define la función que se ejecutará si durante la llamada Ajax se produce un error. Para ello utilizamos el evento
ajaxError
, al que asociamos una función anónima que, simplemente, cargará en el desplegable secundario el texto "Categoría incorrecta" y lo dejará deshabilitado.Por último, utilizamos el método
getJSON
para efectuar la llamada al servidor y realizar la carga del desplegable con la información devuelta. Son tres los parámetros que se le envían al método: - La URL de la acción, obtenida utilizando el helper
Url.Action
que devuelve la dirección de la acción cuyo nombre le pasamos como parámetro. - El objeto, en formato JSON, uyas propiedades representan los parámetros a enviar al controlador.
- La función a ejecutar cuando se reciban datos del servidor. El parámetro de entrada
data
contendrá el array de string con el que tenemos que llenar el desplegable, enviado desde el servidor según la notación JSON.
Aunque el recorrido de este vector y la carga de opciones en el control podría haberse realizado de forma sencilla mediante un bucle, he utilizado el métodoeach
para ilustrar el uso de este tipo de iteradores, tan de moda y muy al estilo funcional empleado, por ejemplo, en las expresiones lambda. Este método recibe dos parámetros; el primero es la colección sobre la cual se va a iterar, y el segundo es una función que se ejecutará para cada uno de los elementos recorridos.
Tercero: el controlador
Es el intermediario en toda esta historia: recibe las peticiones del cliente a través la invocación de acciones, ejecuta las tareas apropiadas y provoca la aparición o actualización de las vistas, utilizando para ello las clases ofrecidas por el Modelo.El controlador define dos acciones: la primera de ellas (Index) es la encargada de cargar los valores iniciales de los desplegables y enviar al usuario la vista correspondiente (Index.aspx). La segunda es la responsable de devolver un objeto en notación JSON con los elementos de la categoría enviada como parámetro.
El código es el siguiente:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewData["ddCategory"] = new SelectList( Datos.GetCategories() );
ViewData["ddElement"] = new SelectList( new [] {"(Selecciona)"} );
return View();
}
public ActionResult GetElements(string category)
{
IEnumerable<string> elements = Datos.GetElementsForCategory(category);
if (elements == null)
throw new ArgumentException("Categoría " + category +" no es correcta");
Thread.Sleep(1000); // Simulamos tiempo de proceso...
return Json(elements);
}
}
Hay varios puntos que me gustaría destacar en este código. En primer lugar, observad que ya las acciones siguen la nueva convención introducida en la preview 3, retornando objetos de tipo
ActionResult
. En el primer método, el return View()
(sin parámetros) hace que el sistema envíe al cliente la vista cuyo nombre coincide con la acción actual (es decir, Index.aspx); en el segundo método se retorna un objeto de tipo JSonResult
que serializará la información suministrada en formato JSON.También es destacable la ayuda introducida en la tercera Preview para llenar listas de formularios utilizando la clase
SelectList
. Como podéis ver, basta con crear en el diccionario ViewData un elemento con el mismo nombre que el del desplegable y asignarle una instancia del SelectList
inicializada con una colección de elementos (cualquier tipo que implemente IEnumerable
). Él se encargará, al renderizar la página, de iterar sobre la colección y crear las etiquetas <option>
oportunas.Asimismo, se puede observar el uso del Modelo en ambos métodos para leer los datos. En este caso se utiliza una clase que encapsularía la lógica de obtención de información, pero nada impediría, por ejemplo, asumir que las clases del Modelo son las generadas desde el diseñador de Linq2Sql y utilizar consultas Linq desde el Controlador.
Observad también el lanzamiento de la excepción cuando la categoría especificada no existe. Lo que llega al navegador en este caso es un error HTTP que es capturado por la función que especificamos para el evento
ajaxError
, haciendo que en el desplegable enlazado aparezca un mensaje de error.Por último, la inclusión de la orden
Thread.Sleep()
es por pura estética, para que se vea lo bien que queda el mensaje "Espere..." en el desplegable mientras carga los datos. En un escenario real este tiempo sería consumido por las comunicaciones cliente-servidor y la obtención de datos desde el modelo, que habitualmente utilizará una base de datos u otro mecanismo de persistencia.
Publicado en: http://www.variablenotfound.com/.

Joe Cartano comentaba hace unas semanas, en el blog oficial del equipo de Visual Web Developer , las nuevas mejoras de este IDE, y en especial las relativas al soporte para plantillas de terceros, y publicó de paso unas estupendas plantillas para la creación de tests unitarios basados en NUnit en aplicaciones ASP.NET MVC.
Para instalarlas, basta con descargar el archivo (con el enlace anterior), descomprimirlo sobre un directorio cualquiera y ejecutar el archivo .BAT correspondiente a la versión de Visual Studio que estemos utilizado, siempre con permisos de administrador. Si todo va bien y suponiendo además que tenemos NUnit instalado, al crear una nueva aplicación ASP.NET MVC en VWD Express aparecerá un cuadro de diálogo como el siguiente:

Esto va en la línea de lo comentado por ScottGu meses atrás, en sus primeros posts sobre el nuevo framework MVC, donde aseguraba que se podría utilizar cualquier framework de testing, citando algunos como NUnit y MBUnit. Y lo de permitir una cierta integración de estos frameworks ajenos a la casa en la versión Express es todo un detalle.
Si se acepta el diálogo, se creará dentro de la misma solución un proyecto de tipo librería que contendrá las referencias a ensamblados necesarios para su ejecución (NUnit, routing, Mvc, etc.) y con un par de métodos de prueba predefinidos. De esta forma, para comprobar el correcto funcionamiento de nuestras aplicaciones sólo tendremos que ejecutar los tests, aunque de momento, y a diferencia de las versiones superiores de Visual Studio 2008, tendrá que ser desde fuera del entorno, utilizando la consola de NUnit:

Publicado en: www.variablenotfound.com.