
using
tiene diversos usos en el lenguaje C#, y seguro que muchos la utilizamos exclusivamente para importar espacios de nombres (namespaces), ignorando el resto de posibilidades que nos ofrece:- Importación de espacios de nombres
- Definición de alias, tanto de espacios de nombres como de tipos.
- Adquisición y liberación de recursos
1. Importación de espacios de nombres
En este caso, la palabra reservadausing
actúa como una directiva del compilador, haciendo que se puedan utilizar tipos definidos en el espacio de nombres importado sin necesidad de especificarlos de forma explícita en el código. using System;
using System.Collections;...
Este es el
using
más común y conocido, así que poco más hay que decir al respecto...2. Definición de alias
Otra forma de utilizarusing
como directiva es crear alias, o nombres cortos alternativos, a namespaces o tipos de datos, que ayuden a evitar conflictos en nombres. Veamos cada uno de ellos.2.1. Alias de espacios de nombres
Puede ser útil cuando tenemos namespaces cuyos nombres coinciden con el de clases, o en situaciones similares que hacen que el compilador no tenga claro qué estamos intentando decirle. Por ejemplo, observad el siguiente código, que no compila, a pesar de ser aparentemente correcto: using System;
namespace Prueba
{
class Saludo
{
public static void Run()
{
Console.WriteLine("hola");
}
}
}
namespace OtroNS
{
class Prueba
{
public static void Main(string[] args)
{
Prueba.Saludo.Run(); // No compila
Console.ReadLine();
}
}
}
El problema es que para acceder a clase que queremos utilizar (
Saludo
) desde un namespace distinto a donde se encuentra definida debemos indicar su ruta completa, es decir, especificar en qué espacio de nombres la encontraremos. Sin embargo, en el ámbito de la clase Prueba
, el compilador piensa que el código Prueba.Saludo.Run()
está intentando acceder a una propiedad de dicha clase, y como no lo encuentra, revienta en compilación.La solución a esto es bien sencilla utilizando los alias, puesto que permiten hacer referencia a un espacio de nombres o un tipo utilizando una denominación diferente, lo que eliminará la ambigüedad. Podemos, por ejemplo, utilizar el alias predefinido
global
, que representa al nivel raíz del árbol de namespaces: ...
public static void Main(string[] args)
{
global::Prueba.Saludo.Run();
Console.ReadLine();
}
...
Otra posibilidad, usando
using
, sería definir un alias personalizado que nos permitiera acceder al espacio de nombres conflictivo utilizando otro identificador: ...
using MiAlias = Prueba;
...
....
public static void Main(string[] args)
{
MiAlias::Prueba.Saludo.Run();
Console.ReadLine();
}
...
Observad el uso de los dos puntos (::) para indicar que el identificador que se encuentra a su izquierda es un alias. Esto puede ayudar a evitar conflictos cuando el nombre del alias coincida con el de una clase en el ámbito de visibilidad actual.
2.2. Alias a tipos
De la misma forma, podemos crear fácilmente alias a un tipo definido, bien para evitar conflictos en nombres como los descritos anteriormente, o bien para hacer más rápido el acceso a los mismos. En el siguiente ejemplo puede observarse su uso: using Strings = System.Collections.Specialized.StringCollection;
using Con = System.Console;
...
Strings s = new Strings(); // 's' es un StringCollection
Con.WriteLine("hola");
Habréis observado que en este caso no se utilizan los dos puntos (::) para separar el alias del resto, puesto que éste no representa a un namespace, sino a un tipo.
3. Adquisición y liberación de recursos
En este caso,using
sirve para especificar bloques de código en los que se van a utilizar recursos que deben ser liberados obligatoriamente al finalizar, como podrían ser conexiones a base de datos, manejadores de ficheros, o recursos del propio sistema operativo. De hecho, salvo en contadas ocasiones, utilizar using
es la forma más recomendable de tratar estos asuntos.En un bloque
using
se definen una serie de recursos, siempre implementando la interfaz IDisposable
, y se delimita un bloque de código en el que éstos serán válidos y visibles. Al salir la ejecución de dicho bloque, estos recursos serán automáticamente liberados llamando a sus respectivos métodos Dispose()
. Y esto se hará siempre, independientemente de si la salida del bloque ha sido de forma natural, mediante una excepción o un salto. En otras palabras, el compilador nos asegura que siempre invocará el método Dispose()
de todos los recursos comprometidos en la operación.Un ejemplo muy habitual lo vemos con las conexiones de bases de datos, recurso valioso donde los haya. La forma correcta de tratarlas sería:
using (SqlConnection conn = new SqlConnection(connectionString))
{
hacerAlgoConLosDatos(conn);
}
// Al llegar aquí, la conexión está liberada. Seguro.
// Además, la variable conn no es visible.
Respecto a la liberación automática de recursos, no hay nada mágico en ello. Internamente, el compilador de C# está transformando el código anterior en:
SqlConnection conn = new SqlConnection(connectionString);
try
{
hacerAlgoConLosDatos(conn);
}
finally
{
if (conn != null)
((IDisposable)conn).Dispose();
}
Además de asegurar que los recursos son liberados cuando ya no van a ser necesarios, tiene también un efecto positivo al hacer que centremos su uso en un bloque compacto, fuera del cual no se podrá acceder a los mismos; por ejemplo, en el caso anterior, dado que la variable
conn
no es visible desde fuera del bloque using
, evitaremos accesos a ella cuando haya sido liberada, que provocaría errores en tiempo de ejecución.Y por cierto, una posibilidad interesante y no demasiado conocida es que se pueden especificar varios recursos en el mismo bloque
using
, de forma que todos ellos se liberen al salir, sin necesidad de tener que anidarlos, siempre que sean del mismo tipo, por ejemplo:
// Anidando usings
using (SqlConnection conn1 = new SqlConnection(connstr1))
{
using (SqlConnection conn2 = new SqlConnection(connstr2))
{
// hacer algo con las dos bases de datos
}
}
// Forma más compacta
using (SqlConnection conn1 = new SqlConnection(connstr1),
conn2 = new SqlConnection(connstr2))
{
// hacer algo con las dos bases de datos
}
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:56 p. m.
Etiquetas: c#, desarrollo, programación

Esto aporta varias ventajas nada despreciables:
- primero, la descarga de estas librerías será, para el cliente, probablemente más rápida que si las tiene que obtener desde tu servidor a través de internet. Se trata de infraestructura de red de Google, y eso implica unas garantías.
- segundo, y relacionada con la anterior, si se trata de un sitio web de alto tráfico, la concurrencia permitida seguramente será infinitamente mayor que la que puedas ofrecer en otro servidor.
- tercero, si el usuario ha visitado previamente otro sitio web que use también la misma librería, se beneficiará del cacheado local de la misma, puesto que su navegador no la descargaría de nuevo. Y en cualquier caso, se estarían aprovechando las optimizaciones de caché de Google.
- cuarto, no consumes ancho de banda de tu proveedor, aunque éste sea despreciable. Y con despreciable me refiero al ancho de banda, no al proveedor ;-)
- quinto, puedes utilizar las librerías desde webs alojadas en algún sitio donde no se pueda, o no sea sencillo, subir archivos de scripts, como la plataforma Blogger desde la que escribo.
En este momento se contemplan los siguientes frameworks, en todas las versiones disponibles:
- jQuery
- jQuery UI
- Prototype
- script_aculo_us
- MooTools
- Dojo
- SWFObject
- Yahoo! User Interface Library (YUI)
Si ya estás utilizando librerías Ajax de Google (como el API de visualización, o el de Google Maps), y las obtienes mediante el cargador google.load(), también puedes utilizarlo para descargar estos frameworks. Asimismo, puedes hacerlo mediante una referencia directa, del tipo:
<script
src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.2/prototype.js">
</script>
Ah, y no hay que preocuparse por los cambios de versiones, ni nada parecido. Google se compromete a alojar indefinidamente todas las distribuciones que vayan publicando, así como de incluir actualizaciones conforme aparezcan.
Por último, y para aportar una visión negativa, hay quien opina que se trata de una estrategia más de Google para obtener información sobre la navegación de los usuarios; la ejecución de código procedente de sus servidores posibilitaría la lectura de cookies y datos que podrían ser utilizados para fines distintos de los previstos en tu web. También hay quienes piensan que podría ser una fuente de difusión de código malicioso si alguien consiguiera hackear estos repositorios. Obviamente, tampoco es buena idea utilizar esta opción si vas a trabajar en modo local, sin conexión.
Para más información sobre las formas de descarga y las librerías disponibles, puedes visitar la guía del desarrollador de las Ajax libraries API.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:58 p. m.
Etiquetas: google, javascript, scripting, servicios on-line, web

- La dirección ha cambiado el nombre del "procedimiento en cascada" por "cascada ágil".
- Se han empezado a contratar consultores para poder echarles las culpas de todo.
- El servidor de integración continua retorna el error "Que te jodan. Me largo".
- Habéis implementado vuestro propio framework en Ruby que usa archivos de configuración XML.
- El miembro del equipo más mayor se refiere a Martin Fowler como "ese gamberro engreído".
- Vuestro sistema de control de código fuente consiste en una serie de carpetas en un disco compartido en red.
- El tiempo asignado para QA es destinado a preguntarse el por qué de ese desastre.
- Todos los requisitos están escritos en una servilleta de papel.
- Empiezas a considerar un cambio de empleo para no tener que mantener la aplicación que estás desarrollando.
- El responsable de desarrollo web piensa que la X de XHTML viene de "eXtremo".
- Las reuniones de todas las iteraciones comienzan por un "¿prefieres las buenas o las malas noticias?".
- El equipo todavía considera que su nivel de CMM es una mierda.
- El progreso se mide por el número de errores corregidos, y no por funcionalidades o características finalizadas.
- La integración continua está haciendo que los empleados nuevos lean el manual del empleado.
- Eres amigo del portero.
- Al SCRUM master no le importa lo que hicisteis ayer, ni lo que haréis hoy.
- Cada hito acaba en un sprint mortal.
- Vuestro mejor desarrollador lo único que tiene es su expediente académico brillante.
- No entendéis los acrónimos DRY, YAGNI o KISS, pero sí WTF, PHB o FUBAR.
- El jefe podría ser sustituido por un script de redirección de emails.
- La única certificación de vuestros procesos de construcción de software es la ISO 9001/2000.
- El jefe piensa que "métrica" es un tipo de bebida proteínica.
- Todos los errores son priorizados como críticos.
- Todas las funcionalidades son priorizadas como triviales.
- Las estimaciones económicas del proyecto mágicamente coinciden con el presupuesto disponible para el mismo.
- Los desarrolladores usan la excusa del código autodocumentado para justificar la ausencia de comentarios.
- Vuestro patrón favorito es el god object.
- Todavía pensáis que compilar es una forma de testear.
- Los desarrolladores todavía utilizan Notepad como entorno de desarrollo.
- El gestor del proyecto pasa 7 horas a la semana pidiendo informes de progreso (basado en hechos reales).
- No tenéis máquina propia, y no estáis programando por parejas.
- Norma del equipo: no hay reuniones hasta las 10:00am, puesto que ayer estuvimos aquí hasta las 2:00am.
- En el equipo se piensa que los ORM son una moda.
- El equipo piensa que la transición desde VB6 a VB.NET será sencilla.
- El gestor piensa que MS Project es la mejor herramienta de gestión de proyectos del mercado.
- Tu esposa sólo consigue verte en una webcam.
- Ninguno de test unitarios tienen aserciones (asserts).
- Vuestro editor de páginas favorito es FrontPage.
- Se discute encendidamente sobre si la llave "{" debe escribirse en una nueva línea, pero se es impacial ante el uso de patrones como MVC.
- El lema de la compañía es "haz más con menos".
- La frase "funciona en mi máquina" se escucha más de una vez al día.
- La última conferencia a la que asistió el equipo de desarrollo .NET fue la Apple Worldwide Developers Conference 2000.
- Los gestores insiten en registrar toda la actividad, pero nunca usan esa información para tomar decisiones.
- Toda la depuración se hace en el servidor en producción.
- El jefe no sabe cómo comprobar el email.
- El jefe piensa que ser compatible SOX significa no trabajar las noches en las que hay béisbol.
- La empresa contrata al senador Ted Stevens para la charla de inicio del proyecto.
- El último libro que leíste fue la Biblia de Visual Interdev 6.
- El presupuesto general se confunde con tu gasto semanal en Mountain Dew.
- El jefe se pasa la hora de la comida llorando en el coche (otro hecho real).
- El responsable de desarrollo web define Ajax como un producto de limpieza.
- Tu jefe espera que pases los dos próximos días creando una solicitud de compra por un componente de 50$.
- El equipo de ventas reduce tus estimaciones porque creen que podéis trabajar más rápidamente.
- Requisito - Rank #1 en Google.
- Todos los días trabajas hasta medianoche, y tu jefe se va a las 16:30.
- A los jefes les encanta decir: "¿por qué se preocupan los desarrolladores? Cobran por horas".
- El personal del turno de noche de StarBucks te conoce por tu nombre.
- El jefe no pueden entender por qué alguien puede necesitar más de un monitor.
- El equipo de desarrollo sólo usa el control de código fuente como sistema de backup por si falla el suministro eléctrico.
- Los desarrolladores no son responsables de realizar ninguna prueba.
- El equipo no usa SVN porque piensan que los algoritmos de fusión (merge) son pura magia negra.
- Tus pizarras no tienen nada escrito (Version One).
- El cliente confunde siempre tu gráfico burn-down con un burn-up (lo que queda por hacer con lo que está hecho).
- El nombre clave del proyecto pasa a ser "Marcha de la muerte".
- Te duele físicamente decir la palabra "sí".
- Tus compañeros no refactorizan, sino refuctorizan.
- Como recompensa por el tiempo extra, tu jefe compra una nueva cafetera.
- El presupuesto de tu proyecto se contabiliza en la empresa como gastos estructurales.
- Puedes bloguear desde el trabajo, gracias a que subcontratas porciones del proyecto.
- Se crea un comité de control de cambios del proyecto, incluso antes de disponer de la primera versión alfa.
- Diariamente consideras romperte los dedos para estar impedido un tiempo.
- El hito final de entrega ha sido renombrado simplemente como "hito", igual que el anterior.
- La política de puertas abiertas de la dirección sólo se aplica desde las 17:00 hasta las 8:00 horas.
- La dirección opina que "por qué comprarlo cuando podemos construirlo".
- Traes cerveza a la oficina durante el segundo turno.
- Descubrís al director del proyecto consultando una tabla Ouija.
- Das información errónea sobre tus compañeros de trabajo para parecer mejor en tu revisión personal.
- Las revisiones de código se planifican para una semana antes del lanzamiento del producto.
- Sólo existe presupuesto para realizar pruebas "si tenemos tiempo".
- El cliente sólo habla sobre los requisitos cuando ya tiene una estimación fija.
- Tu jefe no le encuentra la gracia a Dilbert.
- Comienzas a notar los faroles del jefe durante un planning poker.
- Empiezas a pensar si trabajar dos turnos en Pizza Hut sería una mejor alternativa para tu carrera profesional.
- Todos los problemas de rendimiento se solucionan poniendo máquinas más potentes.
- El proyecto va a ser lanzado como una versión beta permanente.
- Se llevan tu coche del parking por pensar que estaba abandonado.
- El jefe de proyecto suele garabatear durante las reuniones de toma de requisitos.
- Estás utilizando MOSS 2007.
- Tu equipo SCRUM consiste en una única persona.
- Tu hoja de control de horas parece un ticket de Powerball.
- El desarrollador web piensa que 508 tiene que ver con sus pantalones Levi's.
- Piensas que necesitas medicación para la personalidad múltiple porque eres Mort, Elvis, and Einstein al mismo tiempo.
- Tu jefe sustituye el asesoramiento profesional de un consultor por una bola mágica.
- Sabes exactamente cuántos warnings en compilación provocan que tu IDE genere una excepción de "fuera de memoria".
- A estas alturas, todavía no sabes a qué me refiero con el término "IDE".
- Has copiado y pegado código desde The Daily WTF.
- Los tests unitarios que fallan son eliminados porque, obviamente, están obsoletos.
- Eres enviado a una conferencia a aprender, pero te saltas las sesiones para ir a ver si pillas algo.
- El personal de QA te apoda "Jefe Off-by-one".
- Tenéis el 90% del software completo el 90% del tiempo.
- "Oh, oh, casi se me olvida. Ah, voy a necesitar que vengáis también este domingo... gracias".
Post original: 101 Ways To Know Your Software Project Is Doomed
Publicado en: Variable not found
Publicado por José M. Aguilar a las 11:48 p. m.
Etiquetas: curiosidades, desarrollo, desastres, humor, proyectos

Aunque seguro que todos hemos trabajado con profesionales que consideramos
Y eso mismo debió pensar G. Gordon Schulmeyer cuando escribió, a principio de los 90, el paper "The Net Negative Producing Programmer" para la publicación American Programmer (hoy en día Cutter IT Journal), en el que se describía detalladamente qué son los NNPPs, cómo podemos reconocerlos, los motivos de su existencia, y los posibles remedios a aplicar cuando se detectan en un equipo de trabajo.
Según se manifiesta en este documento, los NNPP no son casos extremos. De hecho, en un equipo de diez desarrolladores pueden existir desde uno hasta tres NNPP, lo cual no es ninguna tontería: entre el 10 y el 30% del equipo de trabajo podría estar contribuyendo de forma negativa al éxito del proyecto. En otras palabras, en lugar de desarrollar estarían desdesarrollando, si me permite el amigo Andrés Panitsch que le tome prestado brevemente el nombre de su genial blog.
Aunque pueda parecer lo contrario, la detección objetiva de los programadores con producción neta negativa no es sencilla. Schulmeyer propone la utilización de un modelo de comportamiento donde se evalúen, al menos, las habilidades para:
- escribir un programa
- encontrar y depurar errores
- ampliar un software para adaptarlo a nuevas necesidades
- adquirir nuevos conocimientos técnicos
- comprender un determinado problema
Salvo el último punto, de ámbito más abstracto, existen métricas que ayudan a determinar hacia dónde se inclina la balanza cuando comparamos la productividad de un desarrollador con su ratio de introducción de defectos en el software. Sin embargo, además de los aspectos técnicos, existen impedimentos éticos, y a veces incluso legales, que impedirían la obtención de conclusiones directas a partir de registros de actividad.
Pero probablemente, para poder detectar y evitar la aparición o proliferación de NNPPs en las organizaciones es importante conocer las causas de su existencia. Un estudio citado en el artículo revela causas como la insatisfacción en el trabajo, identificación e implicación nulas con el proyecto, percepción de escasa relación entre profesionalidad y recompensa, y falta de profesionalidad. Es obvio que, transcurridos quince años, siguen siendo válidas hoy en día; y curioso que muchas de ellas sean más atribuibles a la compañía y sus gestores que a los propios profesionales sospechosos de producir en negativo, normalmente por utilizar políticas restrictivas, estresantes, opacas y poco motivadoras para su personal.
La solución para estas situaciones pasa, en primer lugar, por realizar un análisis introspectivo de las condiciones de la organización. Mejorar la comunicación y el establecimiento de objetivos claros y comunes para un equipo de trabajo, por ejemplo, es una medida que puede mejorar bastante la implicación en un proyecto; o la recompensa -no necesariamente económica- por la consecución de objetivos puede incrementar la motivación y autoestima del grupo, y redundar positivamente en la producción.
Respecto al desarrollador, salvo en casos donde existen problemas estructurales graves como la falta total de vocación o capacidad, existen diversas vías para reconducir la situación.

A veces, la producción negativa es un simple reflejo de actitudes desorganizadas, procrastinación, socialización excesiva, no finalización de tareas, estrés constante, falta de información, y otras muchas. Estas sesiones pueden servir para dar con las causas y acabar con la baja productividad de forma rápida.
Otra posibilidad para solucionar los problemas de productividad es la reasignación, el cambio hacia tareas más acordes con las habilidades y puntos fuertes de la persona. Por ejemplo, un NNPP dedicado habitualmente a la codificación podría convertirse en un buen verificador, o documentador, haciendo que sus aportaciones al proyecto pasaran a ser de signo positivo.
El último recurso es la destitución, que debería aplicarse únicamente una vez agotadas alternativas, digamos "menos violentas", como las citadas anteriormente. Lo normal es que un aviso lo suficientemente claro baste para despertar a cualquiera de su letargo, y no sea necesario llegar a mayores.
En cualquier caso, no cabe ninguna duda es del alto coste de los programadores con producción negativa neta. Un retraso en un proyecto o el lanzamiento de productos defectuosos puede tener un impacto terrible en la imagen de una empresa, y en el peor de los casos, hasta puede ocasionar desastres de magnitudes considerables. Y por no hablar de consecuencias internas, como la ruptura de la cohesión en equipos de trabajo, disminución global de productividad, aumento de desconfianza del grupo, incremento de costes, y un largo etcétera.
Semanas atrás Jay Field hablaba también de efectos nefastos para la propia industria del desarrollo de software, porque estos profesionales podían llegar a frenar el avance y la introducción de nuevas tecnologías, e incluso del terrible daño que se puede causar a las próximas generaciones de desarrolladores que durante su proceso de formación y adquisición de experiencia sean puestos a cargo de NNPPs.
Lamentablemente, los desarrolladores con producción neta negativa están aquí para quedarse. Tendrán hueco siempre que existan empresas donde no se cuiden detalles como el ambiente de trabajo, la transparencia, la comunicación, no se fomente la implicación y motivación del trabajador, o cuyos criterios de selección de personal consistan en elegir siempre a los profesionales de menor coste.
Enlaces:
- NNPP en la Wikipedia
- The Net Negative Producing Programmer (PDF)
- The cost of net negative producing programmer
- Why Net Negative Producing Programmers are Here to Stay
Publicado en: www.variablenotfound.com.

Se trata de un sitio web interactivo en el que se encuentran un total de 170 ejemplos de uso de las siguientes API de Google:
- API de visualización, que permite a los desarrolladores acceder a datos estructurados y mostrarlos en una gran variedad de formatos, como tablas o gráficos estadísticos.
- API Ajax para búsquedas, que facilita la incorporación de capacidades de búsqueda de cualquier tipo (páginas, direcciones, multimedia, etc.) en sitios web utilizando javascript.
- API Ajax de idioma, que nos permite acceder mediante javascript a las herramientas de detección de idioma, traducción y transliteración de Google.
- API de datos de Blogger, que permite el acceso con Ajax a información sobre blogs, posts y comentarios de esta plataforma de publicación.
- API de bibliotecas Ajax, la red de distribución de librerías estándar como jQuery, jQuery UI, Prototype, script.aculo.us, MooTools o Dojo.
- API de Google Maps, con el que podremos integrar Google Maps en nuestras webs y utilizar los servicios de localización y posicionamiento que nos ofrece.
- API de Google Earth, el cual nos facilita la inclusión del sistema Google Earth en webs, así como la interacción con ellos vía javascript.
- API Ajax para feeds, un conjunto de funciones que nos permiten obtener feeds de otras páginas sin necesidad de crear proxies de servidor.
- API de Google Calendar, el interfaz a través del cual podemos crear aplicaciones totalmente integradas con Google Calendar.
Pero, al menos para mí, lo mejor viene ahora: dispone de un editor de código fuente en el que podemos modificar dichos ejemplos, ejecutarlos sobre la marcha e incluso guardar o exportar los cambios que realicemos, por lo que resulta de lo más didáctico y efectivo para hacernos con el manejo de estas potentes herramientas.
Enlace: Ajax API Playground.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:48 p. m.
Etiquetas: ajax, desarrollo, google, javascript, programación, servicios on-line, web

@Page
y @Control
que suelen encabezar nuestros archivos .Master, .aspx y .ascx para asignar valores a propiedades de nuestras clases, como en el siguiente ejemplo:<%@ Page Language="C#" MasterPageFile="~/Site1.Master"
AutoEventWireup="true"
CodeBehind="Noticias.aspx.cs"
Inherits="MiPortal.Noticias"
Title="Noticias"
CodigoSeguridad="CD001"
%>
Para conseguirlo, basta con que la página o control herede de una clase que incluya propiedades públicas con el mismo nombre de el atributo que queremos usar. Bueno, en realidad, por cortesía de la herencia, la propiedad podría estar definida en cualquiera de sus tipos antecesores. Gracias a ello, podemos establecer mecanismos de control fuertes para asegurar la presencia de estos atributos en las directivas de página, por ejemplo:
public class MyBasePage: System.Web.UI.Page
{
private string codigoSeguridad;
public string CodigoSeguridad
{
get { return codigoSeguridad; }
set { codigoSeguridad = value; }
}
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
if (string.IsNullOrEmpty(this.CodigoSeguridad))
throw new ArgumentException("CodigoSeguridad no definido");
}
}
Si ahora hacemos que todas nuestras páginas hereden de esta clase sustituyendo a la
Page
estándar, estaremos forzando a que se defina el atributo CodigoSeguridad
en las directivas de todos los aspx (lo mismo es aplicable). Para ello, en el archivo CodeBehind(.cs ó .vb) de las páginas deberíamos sustituir la definición por defecto por algo parecido a
public partial class Noticias: MyPage
{
...
Como curiosidad, la propiedad se establece antes del evento
PreInit
, por lo que a partir de este momento del ciclo de vida de la página, podemos usar su contenido de forma segura. Además, admite cualquier tipo de dato que el sistema sea capaz de convertir desde un string; podéis probar, por ejemplo, a crear una propiedad de tipo Color
o IPAddress
y la plataforma realizará la conversión de forma automática. Eso sí, para usar tipos valor (int
, bool
...) será conveniente hacer uso de los nullables para poder recoger de forma apropiada la ausencia de la asignación del atributo, preguntando por HasValue(), así:
private bool? mostrarBanner;
public bool? MostrarBanner
{
get { return mostrarBanner; }
set { mostrarBanner= value; }
}
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
if (!mostrarBanner.HasValue)
throw new ArgumentException
("MostrarBanner no definido");
}
A nivel de diseño estos atributos no aparecerán como opciones disponibles, según intellisense, al teclear la directiva
@Page
; además, si incluís un atributo personalizado de este tipo, el diseñador de Visual Studio 2008 generará un aviso indicando que no es válido; la versión 2005 os mostrará un error, pero podéis ignorarlos tranquilamente en ambos casos:Validación (ASP.Net): 'CodigoSeguridad' no es un atributo válido de elemento 'Page'Y para finalizar, todo lo dicho es válido para las directivas @Control de los controles de usuario, salvo en lo referente al evento
PreInit
, pero podríamos usar Init
en su lugar sin muchas contraindicaciones.Publicado en: http://www.variablenotfound.com/.

Un detalle que llama la atención al añadir una página maestra a un proyecto ASP.NET desde Visual Studio 2008 es que, por defecto, añade dos secciones de contenido (
ContentPlaceHolder
) a la estructura de la página. Una de ellas es la habitual, en el cuerpo de
<form runat="server">
, que es donde las páginas basadas en esa MasterPage
introducirán sus contenidos y controles. La otra, sin embargo, es una novedad respecto a versiones anteriores del IDE: en la sección <head>
del documento:<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>
Como habréis deducido, esto nos permite introducir contenidos personalizados en la sección
<head>
de una página concreto, como meta tags, o referencias a scripts que deseamos que se carguen con la página, evitando tener que incluirlos mediante programación. Así, si por ejemplo deseamos introducir una referencia a la librería jQuery en una página, la implementación de ésta incluiría los dos placeholders, tal y como sigue:<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<script type="text/javascript" src="/scripts/jquery.js"></script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<!-- contenidos del webform -->
</asp:Content>
La buena noticia para los que todavía trabajamos con Visual Studio 2005 es que podemos aplicar esta misma técnica desde esta versión. Aunque por defecto el IDE no incluye el
ContentPlaceHolder
en el encabezado, podemos añadirlo a mano para que quede como en el código mostrado anteriormente, y el efecto será idéntico. Eso sí, a cambio tendremos que aguantar que el entorno nos avise de que la etiqueta no es correcta en ese punto, puesto que sólo VS2008 es capaz de interpretarlo correctamente, pero se trata sólo de un molesto aviso, que no influirá en la compilación o ejecución de las páginas.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:48 p. m.
Etiquetas: asp.net, desarrollo, programación, trucos, vs2008

A continuación enumero las entradas que más visitas han tenido durante 2008, lo cual probablemente es un parámetro objetivo del interés que han despertado y siguen despertando algunos temas. No todas ellas han sido redactadas en 2008, algunas vienen de atrás, pero su popularidad ha hecho que sigan recibiendo visitas a pesar de su antigüedad.
En primer y segundo lugar respectivamente, y con gran diferencia respecto a sus inmediatos seguidores, los posts "Otras 101 citas célebres del mundo de la informática" y "101 citas célebres del mundo de la informática" se llevan la palma. Ambas entradas han sido ampliamente referenciadas, meneadas, citadas, resumidas, e incluso copiadas y pegadas literalmente hasta la saciedad.
El tercer lugar lo ocupa "Bordes redondeados en webs sin esfuerzo con Nifty Corners Cube", un post de 2007 donde comentaba el uso de las librerías Nifty como vía para redondear elementos de páginas web sin luchar contra Photoshop. Gracias a esta continuada afluencia de visitantes escribí NiftyDotNet y algunos posts para presentarlo y comentar sus posibilidades.
A continuación, la cuarta posición la ocupa un breve tutorial sobre cómo "Llamar a métodos estáticos con ASP.NET Ajax", donde describía el uso de Pagemethods para el intercambio de información entre cliente y servidor en aplicaciones web. Como ya ocurrió el año pasado, Ajax sigue siendo una temática por la que muchos lectores se acercan a este rinconcillo de la red, y ha seguido así tras la entrada en escena de jQuery como producto oficial de las herramientas de desarrollo de Microsoft.
La quinta posición va para los "13 consejos para comentar tu código", un post de finales de 2007, que ha continuado atrayendo lectores. Como curiosidad, he de añadir que ha sido traducido al inglés, al chino y no sé si a algún otro más, y al menos en el primero de ellos ha tenido una difusión impresionante.
En el post Las 10 cosas que más fastidian a los programadores comentaba los resultados de una consulta realizada en Stackoverflow sobre factores de irritación frecuentes en los desarrolladores, ampliándola con otros puntos de propia experiencia.
La séptima posición la ocupa la entrada "Evitar el postback al pulsar un botón en ASP.Net", creado a partir del análisis de palabras clave por las que se llegaba a Variable not found, en las que se veía claramente que los problemas con el postback y, en general el modelo de eventos de ASP.NET, eran causas de dolor de cabeza para los desarrolladores. En el post detallaba algunos escenarios por los que podría interesarnos anular la vuelta al servidor de un formulario, describiendo distintos métodos para conseguirlo.
En el puesto número ocho, las "32 técnicas de producción de ideas", enumeraba un buen puñado de técnicas utilizadas para favorecer la creatividad y generar ideas.

Por último, "20 desastres famosos relacionados con el software", una traducción autorizada de un post en inglés donde enumeraba problemas provocados, en mayor o menor medida, por el software.
Ya por debajo de estos se encuentran entradas también muy populares, pero no lo suficiente como para colarse en este Top Ten, como "Crea un traductor en tu web con Google AJAX Language API", "8 Curiosidades sobre los emoticonos", "a qué huele tu código", o los posts sobre ASP.NET MVC, que tímidamente van tomando posiciones en el ranking.
¡Ah, aprovecho para desearos a todos un feliz y próspero 2009! :-)
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:48 p. m.
Etiquetas: autobombo, blogging, variablenotfound, variablenotfound.com

Para el que todavía no esté al tanto de la historia, durante la segunda semana de diciembre ha tenido lugar en Dallas el encuentro de desarrolladores DevConn4, en el que Matt Gretz, destacado miembro del equipo de VB.NET, hacía público el Roadmap que Microsoft tiene previsto para este producto, que no trae buenas noticias para la gran comunidad de desarrolladores en Visual Basic, y que provocó un revuelo impresionante tanto en la sala del evento como en la blogosfera y medios especializados.
Resumidamente, el Roadmap prevé la progresiva desaparición de Visual Basic, mediante un plan de migración que facilitará los desarrolladores pasar a C# en un plazo de tres años. A partir de 2012 no se publicarán nuevas versiones de VB, por lo que, dado que el lenguaje no evolucionará para reflejar los cambios que sean introducidos a nivel de framework, lo llevará irremediablemente a su desaparición en no más de cinco años.
En líneas generales, el contexto actual y el panorama que nos espera, si nadie lo impide, es el siguiente:
- Primero, durante años se han ido introduciendo mejoras en Visual Basic .NET hasta cubrir la mayoría de características del framework e igualarlo en potencia a C#, con objeto de hacer más suave el salto de un lenguaje a otro. Por ejemplo, la inclusión en el actual VB.NET 9 de tal cantidad de novedades y cambios respecto a versiones anteriores, responden claramente a estas necesidades.
Hasta aquí, todo es correcto y aporta exclusivamente ventajas. El problema viene ahora.
- La segunda gran acción podremos verla con el próximo Visual Studio 2010 y .Net 4.0, de los cuales ya es posible descargar previews. Para entonces, Visual Basic aparecerá con el nombre comercial VB# (VB Sharp), dando a entender que se trata de una versión de transición a C#, y en el que podremos encontrar el giro hacia una sintaxis más cercana a este lenguaje, como el uso de llaves en bloques (
if
, blucleswhile
yfor
, etc.), estructuras compactas (como la sintaxis lambda o declaraciones menos verbosas), comentarios tipo C "/*", y otras lindezas que seguro que dejarán nuestro código VB bastante diferente al actual. Eso sí, para facilitarnos la vida, será el propio IDE el que nos ayude a acostumbrarnos a las particularidades sintácticas, sustituyendo sobre la marcha el código VB.NET tradicional por VB#.
En esta fase también encontraremos los cambios que se van a producir en C# para dotarlo de algunas de las ventajas de Visual Basic, como los parámetros opcionales, con objeto de lograr una mayor confluencia y hacer más fácil la adopción del lenguaje por esta comunidad de desarrolladores.
- La última parte del plan se llevará a cabo en 2012 con Visual Studio (codename Moonwalker), que se distribuirá con .NET framework 5.0 (aka Greengarden) y no vendrá acompañado de una nueva versión de Visual Basic, sino de un asistente de migración a C#. Para esas fechas, además, se prevé que la mayoría de desarrolladores de Visual Basic haya adoptado VB#, por lo que el salto será, en palabras de Matt, "no traumático".

Finalmente, comentar que también hemos acordado el emblema de la plataforma pro-salvación de Visual Basic que podemos ir utilizando en nuestras páginas para dar difusión al movimiento hasta que tengamos lista la web oficial, que se prevé finalizada para primeros de año.

Y no olvides que cuanto más difundamos esta iniciativa, más fuerza tendremos ante la multinacional para hacer que se replantee su estrategia.
¡Larga vida a VB.NET!
Obviamente la noticia no es real, se trata simplemente de una broma del Día de los Inocentes, pero en cualquier caso... ¡Larga vida a VB! :-D
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 12:10 a. m.
Etiquetas: desarrollo, inocentadas, programación, vb.net
Feliz navidad, amigos. Y sobre todo, pasadlo bien. ;-)
Publicado en: www.variablenotfound.com.
"Se canceló la navegación a la página web. Puede intentar lo siguiente: volver a escribir la dirección"

El índice de contenidos funcionaba; el alfabético también; incluso la búsqueda por palabras se ejecutaba correctamente, pero sin embargo, al pulsar sobre una sección en el panel izquierdo, aparecía la pantalla anterior en lugar del contenido deseado.
Tras meses culpando al equipo o a la calidad de los archivos que ponen algunos a descargar, por fin me he dado cuenta de que se trata de una medida de seguridad para protegerse de contenidos procedentes de equipos remotos, todos ellos potencialmente diabólicos.
Al parecer, si el archivo de ayuda lo estás abriendo desde una unidad de red, probablemente no te dejará hacerlo, a no ser que indiques a tu equipo que se trata de una fuente de confianza (en el Centro de Ayuda y Soporte de Microsoft puedes encontrar distintas formas de hacerlo, tocando el registro de Windows). La solución más sencilla en este caso sería copiarlo a tu equipo.
Si el archivo de ayuda .CHM te lo has descargado de internet, tu equipo lo habrá bloqueado para evitar que algún código malicioso te cambie los planes del día, así que para acceder a su contenido debes desbloquearlo, accediendo a la opción Propiedades del menú contextual del fichero, y pulsando el botón Desbloquear, como se muestra en la siguiente captura:

Publicado en: www.variablenotfound.com.

La forma de conseguirlo es muy sencilla, y básicamente aprovecha la técnica utilizada por Nifty Corners Cube, la librería javascript encapsulada por NiftyDotNet, para crear el efecto de redondeo de los ángulos de elementos de bloque de una página Web.
Lo primero que debemos hacer es incluir la imagen en nuestra página dentro de la habitual etiqueta
<img>
, pero eso sí, dentro de un elemento contenedor, que es al que aplicaremos el efecto de redondeo:
<div class="fotonifty"
style="background: url(images/paisaje1.jpg) no-repeat top left;" >
<img src="images/paisaje1.jpg" alt="Magnífico paisaje" />
</div>
[...]
/* Estilos de la página */
<style type="text/css">
.fotonifty
{
width: 150px;
height: 150px;
margin: 10px;
}
.fotonifty img
{
display: none;
}
</style>
Fijaos que la etiqueta
<img>
sigue existiendo, conservando la semántica y características de accesibilidad del marcado, pero la estamos ocultando desde CSS definiéndole un display: none
. La que se verá en la web es la definida como fondo del <div>
en el estilo.Observad también que hemos tenido que indicar el ancho y alto del
<div>
. Esto es absolutamente necesario para que éste tome el tamaño necesario para mostrar la imagen completa.Ya sólo nos falta aplicar el efecto de redondeo deseado a los elementos
<div class="fotonifty">
. Con NiftyDotNet, basta con arrastrar y soltar el componente sobre nuestro formulario web, o bien introducir a mano el control, y establecer sus propiedades correctamente: <cc1:Nifty ID="Nifty1" runat="server"
Selectors="div.fotonifty"
CornerSize="Big"
FixedHeight="true" />
La propiedad
Selectors
se ha establecido con el selector CSS que identifica los bloques a redondear, y CornerSize
define el tamaño del borde. FixedHeight
es necesaria, e indica que el proceso Nifty no debe modificar el alto del elemento, pues está definido a nivel de estilos.En fin, un truco que puede ser especialmente interesante en contextos donde las imágenes que queremos mostrar redondeadas no forman parte del diseño base de una aplicación web, sino de los contenidos gestionados por los usuarios.Enlaces:Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:52 p. m.
Etiquetas: asp.net, desarrollo, niftydotnet, trucos, web

ASP.NET MVC viene de fábrica con un buen conjunto de helpers, como los que podemos encontrar en el espacio de nombres
System.Web.Mvc.Html
, que nos facilitan la creación de elementos de la página y la introducción de ciertos automatismos. Por ejemplo, si en lugar de escribir en la Vista el código XHTML correspondiente a un cuadro de edición realizamos una invocación del helper, así: <%= Html.TextBox("name") %>
, estaremos generando la etiqueta de forma totalmente correcta, y cargando el valor por defecto si en el ViewData
existe una entrada con dicho nombre.Sin embargo, es obvio que los helpers suministrados no cubren todo lo que vamos a requerir para desarrollar de forma productiva aplicaciones basadas ASP.NET MVC, ni siquiera una pequeña parte, por lo que lo lógico es que terminemos desarrollando nuestras propias funciones a base de generalizar las soluciones a problemas y distintos escenarios con los que nos vayamos encontrando.
Desde hace tiempo tenía interés por crear un helper medianamente complejo para ver los problemas con los que podía encontrarme... y no hay nada como un fin de semana climatológicamente desapacible para dedicarse a estos menesteres.
El resultado ha sido
LinkDropDownLists
, un helper para el framework ASP.NET MVC 1.0 (abril 2009), cuya función es enlazar de forma muy sencilla dos o más desplegables, recargando mediante Ajax (gracias a jQuery) los contenidos cuando alguno de ellos cambie. En otras palabras, se trata de un sistema de desplegables en cascada como el que describí hace unos meses en "Desplegables en cascada con ASP.NET MVC y jQuery", pero en formato helper, muy flexible y cómodo de utilizar, y adaptado a la versión disponible del framework.Introducción
LinkDropDownLists
es un método de extensión de la clase AjaxHelper
, que nos permite "encadenar" entre sí un conjunto de desplegables, de forma que el cambio de valor de uno de ellos provoque, en cascada, la recarga del resto siguiendo el orden en el que han sido vinculados.La recarga se realizará obteniendo los datos mediante una petición Ajax con jQuery a una acción del controlador desde el que se ha generado la Vista, que retornará los elementos en formato JSON, y serán introducidos automáticamente en el desplegable correspondiente.

El método
LinkDropDownLists
lo utilizaremos en la Vista para generar los scripts necesarios para realizar de forma automática la comunicación con el servidor cada vez que cambie un desplegable; la recepción de la llamada Ajax, por otra parte, requerirá una acción en el Controlador, que será la responsable de obtener la información desde el Modelo y retornarlos a la vista para materializarlos como elementos de los controles visuales.La Vista
Para utilizar el helper, antes de nada hay que asegurarse de que jQuery está incluido en la vista o su página maestra. Dado que MVC framework desde su versión Beta 1 incluye esta librería en las plantillas por defecto, sólo es necesario referenciarla desde el código HTML, por ejemplo: <script src="/scripts/jquery-1.2.6.js"
type="text/javascript"></script>
A partir de este momento, podremos utilizar sin problema el helper de la forma que se describe a continuación, siempre que haya sido incluido el espacio de nombres donde fue definido, por ejemplo usando la directiva de página
Import Namespace="Jma.Mvc.jQuery.Extensions"
, o en la sección <namespaces>
del archivo Web.config.Dado que tanto las vistas que heredan de
ViewPage
o ViewPage<T>
(en la práctica, todas) como los controles ViewUserControl
, disponen de una propiedad de tipo AjaxHelper
llamada Ajax
, podremos invocar los métodos de extensión de dicho tipo desde el código ASPX o ASCX de forma muy sencilla: <%= Ajax.LinkDropDownLists(...)%>
Vamos a mostrar algunos ejemplos de uso del helper
LinkDropDownLists
, imaginando un formulario en el que existe un desplegable llamado "Pais" (es decir, un <select id="Pais">
), otro llamado "Provincia" y un último llamado "Ciudad", tales que un cambio en el primero debería forzar una recarga del segundo, y éste una recarga del tercero.Utilizando el helper
LinkDropDownLists
, sólo sería necesario introducir el siguiente código en la vista: <%= Ajax.LinkDropDownLists(
new [] {"Pais", "Provincia", "Ciudad"}
)
%>
¡Ya está! Esto sería todo lo que habría que hacer en la capa cliente para conseguir enlazarlos. Como puede deducirse, mediante esta orden estaríamos creando una cadena de dependencia entre los tres desplegables, de forma que un cambio en cualquiera de ellos forzaría la recarga de los definidos tras él. El helper se encargará de generar el código script que este mágico comportamiento posible.
Pero compliquemos un poco más el escenario. Si, además, en el mismo formulario se encontrara otro conjunto de desplegables, podríamos enlazarlos entre sí usando la misma llamada, especificando en dos arrays independientes las distintas cadenas de vínculos, como sigue:
<%= Ajax.LinkDropDownLists(
new [] {"Pais", "Provincia", "Ciudad"},
new [] {"Marca", "Modelo" }
)
%>
Y aún cabe una vuelta de tuerca más; si dependiendo de la selección en "Pais" fuera necesario cargar otro desplegable, digamos, "Idioma" que mostrara las lenguas usadas en el mismo, podríamos añadir una tercera cadena de enlaces en la que aparecería de nuevo el desplegable "Pais" vinculado al idioma:
<%= Ajax.LinkDropDownLists(
new [] {"Pais", "Provincia", "Ciudad"},
new [] {"Marca", "Modelo" },
new [] {"Pais", "Idioma" }
)
%>
Como se puede deducir de los ejemplos, cada uno de los parámetros consiste en un array de strings que contiene los identificadores de los desplegables, en el mismo orden en que deben ser recargados. Estos controles pueden estar definidos en cualquier punto de la Vista, bien directamente en HTML o bien mediante el helper
Html.DropDownList()
incluido en el MVC framework.Por último, el método
LinkDropDownLists()
dispone de un buen conjunto de sobrecargas, que nos permitirán modificar los siguientes aspectos de su comportamiento por defecto:- workingMessage: mensaje que muestra en el desplegable mientras se están obteniendo los datos del servidor.
- errorMessage: mensaje a mostrar cuando se produce un error de conexión, o se lanza una excepción desde el servidor.
- javascriptCallbackFunction: nombre de la función javascript que se ejecutará cuando se han obtenido datos del servidor y se ha recargado un desplegable.
- actionName: nombre de la acción en el controlador (por defecto
GetDropDownElements()
). - imgSrc: URL de la imagen de progreso de carga mostrada durante la petición Ajax (por defecto, "/content/ajax-loading.gif").
- mainFunctionName: nombre de la función principal que genera el helper (por defecto, loadDropDownList).
El controlador
En el lado servidor, necesitamos una acción en el controlador desde el que se esté lanzando la vista que sea la encargada de procesar las peticiones enviadas desde la capa cliente y retornar los elementos que poblarán el desplegable. Por defecto, esta la acción se llamaráGetDropDownElements
, aunque puede modificarse utilizando las sobrecargas del helper descritas anteriormente.Para que pueda disponer de toda la información de contexto necesaria, a esta acción se le pasan los siguientes parámetros de forma automática desde la Vista:
- source: el desplegable que ha cambiado.
- value: el nuevo valor que ha tomado.
- text: el texto mostrado en el desplegable.
- index: el índice del elemento seleccionado.
- target: el nombre del desplegable a cargar.
La firma del método deberá contener los parámetros que necesite de los anteriores, no siendo obligatorio ninguno de ellos. Las siguientes signaturas, por tanto, serían válidas, aunque la segunda permitirá acceder a más información sobre la situación en cliente al producirse la invocación Ajax:
public ActionResult GetDropDownElements(string target)
{ ... }
public ActionResult GetDropDownElements(
string source, string value,
string text, int index, string target)
{ ... }
Dentro de la acción, lo lógico será utilizar el Modelo para obtener los elementos que pueblen el desplegable
target
. Por ejemplo, si recibimos una petición indicando que debemos llenar el desplegable de provincias debido a un cambio de país (source=="Pais" && target=="Provincia"
), deberemos realizar una consulta en el almacén de datos filtrando aquellas cuyo identificador de país sea el contenido en el parámetro value
.Si no encontramos datos para devolver, el retorno de la función será un
string
serializado en JSON, indicando el error. Este mensaje será mostrado como contenido del desplegable. ...
return Json("No se han definido provincias para " + text);
En caso contrario, es decir, si disponemos de elementos para rellenar el desplegable, el retorno será una colección de objetos que deberán presentar las siguientes propiedades públicas:
- Value: con el valor del elemento (el
value
deloption
). - Text: que contendrá el texto que será mostrado en el desplegable.
- Selected: un booleano que indicará si el elemento deberá ser la selección por defecto una vez poblado el desplegable.
// Generando los elementos de forma manual...
List<object> elements = new List<object>();
elements.Add(new { Value = 1, Text = "Primero" });
elements.Add(new { Value = 2, Text = "Segundo" });
elements.Add(new { Value = 3, Text = "Tercero" });
elements.Add(new { Value = 4, Text = "Cuarto", Selected = true });
return Json(elements);
// O usando Linq...
var elems = from p in Model.ObtenerProvincias(value)
select new
{
Text = p.NombreProvincia,
Value = p.IdProvincia
};
return Json(elems);
Proyecto de demostración
Al pie del post hay un enlace a Skydrive desde donde podréis descargar un proyecto de demostración del helperLinkDropDownLists
para ver algunas de sus características en funcionamiento:- una única página con dos grupos independientes de desplegables enlazados
- algunos desplegables definidos mediante helpers y en HTML.
- retorno de mensajes de error desde el servidor
- captura de excepciones y errores de comunicación
- función callback de notificación de llenado de desplegables
- utilización de textos personalizados

Enlaces: Descargar proyecto para Visual Studio 2008 SP1 + ASP.NET MVC 1.0.
(También funciona con Visual Web Developer Express 2008 SP1).
Publicado en: www.variablenotfound.com.

Se trata de un componente con una versión específica para ASP.NET, válida para WebForms y MVC framework, y otra para Windows Forms, que permite generar gráficas estadísticas prácticamente de cualquier tipo, visualmente muy atractivas, realmente fáciles de utilizar en nuestas aplicaciones y, además, de forma gratuita.
Enumero características interesantes, o que me han llamado la atención (ambas cosas no están necesariamente unidas ;-)), del control para ASP.NET:
- El control se renderiza en cliente con una etiqueta
<img>
. - Se puede forzar al control a generar las imágenes al vuelo o a almacenarlas físicamente en una carpeta.
- Las imágenes generadas pueden ser cacheadas para mejorar el rendimiento.
- Genera BMPs, JPGs, PNGs o EMFs.
- Permite también usarlo con aplicaciones no ASP.NET 3.5 a través del modo "binary streaming", que fuerza a que el control elimine toda la salida HTML de la página donde se encuentra y retorne únicamente la imagen como resultado, de forma dicha página puede ser utilizada como source de un tag
<img>
en otro sitio. - Soporta eventos del tipo "PrePaint" y "PostPaint" para poder hacer retoques a mano sobre los resultados, como:
void Chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
e.ChartGraphics.Graphics.DrawString("Hola",
new Font("Arial", 12f),
Brushes.Black, 10, 10);
} - 25 tipos de gráficas, muchas de ellas con vistas en tres dimensiones, en las que se puede modificar prácticamente todo: rotación, inclinación, sombras, etc.
- Podemos crear imágenes con múltiples gráficas distintas, utilizar en ellas todas las series de datos que deseemos, con un número ilimitado de puntos.
- Control total sobre los ejes en cuanto a escalado, visualización o etiquetado.
- Posibilidad de añadir anotaciones, leyendas y otros elementos "extra".
- Permite establecer datos enlazando el control a fuentes (binding), o de forma manual sobre el mismo utilizando los diseñadores o etiquetas ASP.NET.
- Soporta mapeo de imágenes, posibilidad de capturar clicks sobre áreas para establecer comportamientos personalizados, o combinarlo con Ajax para enriquecer la experiencia de usuario.
Instalación
Antes de instalar, asegúrate que cumples el requisito previo básico, tener instalado Microsoft .NET Framework 3.5 SP1. Si no lo has hecho antes, ya sabes por dónde empezar ;-)Una vez asegurado este punto, el siguiente paso es descargar Microsoft Chart Control, que incluye controles tanto para ASP.NET como para Windows Forms. Existe también, como descarga opcional, el paquete de idioma para Microsoft Chart Control, que contiene la localización del producto para otros idiomas.
Después, es una buena idea instalar el Add-on para Visual Studio 2008 que os facilitará el trabajo con el control desde este entorno de desarrollo, a base de diseñadores integrados. No olvidéis también bajaros también la documentación si váis a necesitar información detallada de las librerías incluidas.
Y, por último, para tomar conciencia del tipo de resultados que se pueden obtener con este control, el ideal es descargar los proyectos de demostración, que os permitirán ver y tocar una auténtica batería de ejemplos seguro muy útiles a la hora de usarlo en vuestros desarrollos, tanto ASP.NET como Winforms.

Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:20 p. m.
Etiquetas: asp.net, componentes, productividad, vs2008, web

Esto, unido a un comentario de Julio sobre el propio post en el que preguntaba si existía algo parecido en Visual Basic .NET, ha hecho que reedite el mismo, pero centrándome esta vez en dicho lenguaje.
Los métodos genéricos son interesantes herramientas que están con nosotros desde los tiempos del .NET Framework 2.0 y pueden resultarnos muy útiles de cara a la construcción de frameworks o librerías reutilizables.
Podríamos considerar que un método genérico es a un método tradicional lo que una clase genérica a una tradicional; por tanto, se trata de un mecanismo de definición de métodos con tipos parametrizados, que nos ofrece la potencia del tipado fuerte en sus parámetros y devoluciones aun sin conocer los tipos concretos que utilizaremos al invocarlos.
Vamos a profundizar en el tema desarrollando un ejemplo, a través del cual podremos comprender por qué los métodos genéricos pueden sernos muy útiles para solucionar determinado tipo de problemas, y describiremos ciertos aspectos, como las restricciones o la inferencia, que nos ayudarán a sacarles mucho jugo.
Escenario de partida
Como sabemos, los métodos tradicionales trabajan con parámetros y retornos fuertemente tipados, es decir, en todo momento conocemos los tipos concretos de los argumentos que recibimos y de los valores que devolvemos. Por ejemplo, en el siguiente código, vemos que el métodoMaximo
, cuya misión es obvia, recibe dos valores Integer
y retorna un valor del mismo tipo: Function Maximo(ByVal uno As Integer, ByVal otro As Integer) _
As Integer
If uno > otro Then Return uno
Return otro
End Function
Hasta ahí, todo correcto. Sin embargo, está claro que retornar el máximo de dos valores es una operación que podría ser aplicada a más tipos, prácticamente a todos los que pudieran ser comparados. Si quisiéramos generalizar este método y hacerlo accesible para otros tipos, se nos podrían ocurrir al menos dos formas de hacerlo.
La primera sería realizar un buen puñado de sobrecargas del método para intentar cubrir todos los casos que se nos puedan dar:
Function Maximo(ByVal uno As Integer, ByVal otro As Integer) _
As Integer
' ...
End Function
Function Maximo(ByVal uno As Long, ByVal otro As Long) _
As Long
' ...
End Function
Function Maximo(ByVal uno As Decimal, ByVal otro As Decimal) _
As Decimal
' ...
End Function
' Y así hasta que te aburras...
Obviamente, sería un trabajo demasiado duro para nosotros, desarrolladores perezosos como somos. Además, según Murphy, por más sobrecargas que creáramos seguro que siempre nos faltaría al menos una: justo la que vamos a necesitar ;-).
Otra posibilidad sería intentar generalizar utilizando las propiedades de la herencia. Es decir, si asumimos que tanto los valores de entrada del método como su retorno son del tipo base
Object
, aparentemente tendríamos el tema resuelto. Lamentablemente, al finalizar nuestra implementación nos daríamos cuenta de que no es posible hacer comparaciones entre dos Object
's, por lo que, o bien incluimos en el cuerpo del método código para comprobar que ambos sean comparables (consultando si implementan IComparable
), o bien elevamos el listón de entrada a nuestro método, así: Function Maximo(ByVal uno As IComparable, ByVal otro As Object) As Object
If uno.CompareTo(otro) > 0 Then Return uno
Return otro
End Function
Pero efectivamente, como ya habréis notado, esto tampoco sería una solución válida para nuestro caso. En primer lugar, el hecho de que ambos parámetros sean
Object
o IComparable
no asegura en ningún momento que sean del mismo tipo, por lo que podría invocar el método enviándole, por ejemplo, un String
y un Integer
, lo que provocaría un error en tiempo de ejecución. Y aunque es cierto que podríamos incluir código que comprobara que ambos tipos son compatibles, ¿no tendríais la sensación de estar llevando a tiempo de ejecución problemática de tipado que bien podría solucionarse en compilación?El método genérico
Fijaos que lo que andamos buscando es simplemente alguna forma de representar en el código una idea conceptualmente tan sencilla como: "mi método va a recibir dos objetos de un tipo cualquiera T, que implementeIComparable
, y va a retornar el que sea mayor de ellos". En este momento es cuando los métodos genéricos acuden en nuestro auxilio, permitiendo definir ese concepto como sigue: Function Maximo(Of T As IComparable) _
(ByVal uno As T, ByVal otro As T) As T
If uno.CompareTo(otro) > 0 Then Return uno
Return otro
End Function
En el código anterior, podemos distinguir una porción de código que aparece resaltada justo después del nombre del método, y antes de comenzar a definir sus parámetros. Es la forma de indicar que
Maximo
es un método genérico y operará sobre un tipo cualquiera al que llamaremos T, y mediante una restricción estamos indicando que deberá implementar obligatoriamenter el interfaz IComparable
(más adelante trataremos esto en profundidad).A continuación, podemos observar que los dos parámetros de entrada son del tipo T, así como el retorno de la función. Si no lo ves claro, sustituye mentalmente la letra T por
Integer
(por ejemplo) y seguro que mejora la cosa.Lógicamente, estos métodos pueden presentar un número indeterminado de parámetros genéricos, como en el siguiente ejemplo. Observad que la palabra clave
Of
sólo se indica al principio: Function MiMetodo(Of T1, T2, TResult) _
(ByVal par1 As T1, ByVal par2 As T2) As TResult
Y una aclaración antes de continuar: lo de usar la letra
T
para identificar el tipo es pura convención, podríamos llamarlo de cualquier forma (por ejemplo Maximo(Of MiTipo)(ByVal uno as MiTipo, ByVal otro as MiTipo) As MiTipo
), aunque ceñirse a las convenciones de codificación es normalmente una buena idea.Restricciones en parámetros genéricos
Retomemos un momento el código de nuestro método genérico: Function Maximo(Of T As IComparable) _
(ByVal uno As T, ByVal otro As T) As T
If uno.CompareTo(otro) > 0 Then Return uno
Return otro
End Function
Antes había comentado que en este caso estabamos creando un método que podría actuar sobre cualquier tipo, aunque mediante una restricción forzábamos a que éste implementara, obligatoriamente, el interfaz
IComparable
, lo que nos permitiría realizar la operación de comparación que necesitamos.Obviamente, las restricciones no son obligatorias; de hecho, sólo debemos utilizarlas cuando necesitemos limitar de alguna forma los tipos permitidos como parámetros genéricos, como en el ejemplo anterior. Está permitida la utilización de las siguientes reglas:
As Structure
, indica que el argumento debe ser un tipo valor.As Class
, indica que T debe ser un tipo referencia.As New
, fuerza a que el tipo T disponga de un constructor público sin parámetros; es útil cuando desde dentro del método se pretende instanciar un objeto del mismo.As nombredeclase
, indica que el argumento debe heredar o ser de dicho tipo.As nombredeinterfaz
, el argumento deberá implementar el interfaz indicado.As nombredetipogenérico
, indica que el argumento al que se aplica debe ser igual o heredar del tipo, también argumento del método, indicado por nombredetipogenérico (observad en el siguiente ejemplo el parámetro T2).
Function MiMetodo(Of T1 As {Class, IEnumerable}, _
T2 As {T1, New}, _
TResult As New) _
(ByVal par1 As T1, ByVal par2 As T2) As TResult
' ... Cuerpo del método
End Function
Uso de métodos genéricos
A estas alturas ya sabemos, más o menos, cómo se define un método genérico, pero nos falta aún conocer cómo podemos consumirlos, es decir, invocarlos desde nuestras aplicaciones. Aunque puede intuirse, la llamada a los métodos genéricos debe incluir tanto la tradicional lista de parámetros del método como los tipos que lo concretan. Vemos unos ejemplos: Dim mazinger As String = Maximo(Of String)("Mazinger", "Afrodita")
Dim i99 As Integer = Maximo(Of Integer)(2, 99)
Una interesantísima característica de la invocación de estos métodos es la capacidad del compilador para inferir, en muchos casos, los tipos que debe utilizar como parámetros genéricos, evitándonos tener que indicarlos de forma expresa. El siguiente código, totalmente equivalente al anterior, aprovecha esta característica:
Dim mazinger As String = Maximo("Mazinger", "Afrodita")
Dim i99 As Integer = Maximo(2, 99)
El compilador deduce el tipo del método genérico a partir de los que estamos utilizando en la lista de parámetros. Por ejemplo, en el primer caso, dado que los dos parámetros son
String
, puede llegar a la conclusión de que el método tiene una signatura que coincide con la definición del genérico, utilizando String
como tipo parametrizado.Otro ejemplo de método genérico
Veamos un ejemplo un poco más complejo. El métodoCreaLista
, aplicable a cualquier clase, retorna una lista genérica (List(Of T)
) del tipo parametrizado del método, que rellena inicialmente con los argumentos (variables) que se le suministra: Function CreaLista(Of T)(ByVal ParamArray pars() As T) As List(Of T)
Dim list As New List(Of T)
For Each elem As T In pars
list.Add(elem)
Next
Return list
End Function
' ...
' Uso:
Dim nums = CreaLista(Of Integer)(1, 2, 3, 4, 5, 6, 7)
Dim noms = CreaLista(Of String)("Pepe", "Juan", "Luis")
Otros ejemplos de uso, ahora beneficiándonos de la inferencia de tipos:
Dim nums = CreaLista(1, 2, 3, 4, 5, 6, 7)
Dim noms = CreaLista("Pepe", "Juan", "Luis")
' Incluso con tipos anónimos de VB.NET 9
Dim v = CreaLista( _
New With {.X = 1, .Y = 2}, _
New With {.X = 3, .Y = 4} _
)
Console.WriteLine(v(1).Y) ' Muestra "4"
En resumen, se trata de una característica de la plataforma .NET, reflejada en lenguajes como C# y VB.Net, que está siendo ampliamente utilizada en las últimas incorporaciones al framework, y a la que hay que habituarse para poder trabajar eficientemente con ellas.
Publicado en: www.variablenotfound.com.
Publicado por José M. Aguilar a las 11:41 p. m.
Etiquetas: .net, desarrollo, programación, vb.net, vs2008