Saltar al contenido

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

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

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

¡Microsoft MVP!
jueves, 8 de noviembre de 2007
Leo en Codeville que Matt Gibbs (Program Manager de ASP.NET en Microsoft) ha anunciado hoy mismo, en el contexto de las conferencias TechEd que se están celebrando en Barcelona, que en las próximas semanas se publicará el primer CTP del ASP.NET MVC Framework.

Asimismo, se han vuelto a comentar las principales ventajas de utilizar este nuevo marco para el desarrollo de sistemas web:
  • Separación clara de lógica, presentación y control.
  • Utilización de URLs limpias y amigables.
  • Control absoluto sobre el marcado y emisión de XHTML puro.
  • Extensibilidad total, todos los componentes pueden ser reemplazados por otros de terceros.
  • Ventajas sobre Monorail (o incluso Ruby on Rails), como la perfecta integración con VS2008 (intellisense, plantillas, depuración...), o el uso de parte de la infraestructura ASP.NET (aunque se abandonen los postbacks).

En fin, que en breve tendremos diversión asegurada.
martes, 6 de noviembre de 2007
Días atrás, Daniel Moth, desarrollador de Microsoft, publicaba un interesante post comentando 10 puntos importantes a saber sobre el nuevo Visual Studio 2008 y .NET framework 3.5 y la verdad es que no tienen desperdicio.

1. Lanzamiento
Visual Studio 2008 y .NET framework 3.5 serán lanzados oficialmente juntos el próximo febrero. Sin embargo, estará disponible para desarrolladores a finales de noviembre de 2007.
Afortunadamente, estarán disponibles las versiones Express de C#, VB, C++ y Web, así como las Profesionales (¡con soporte de testeos unitarios!), Estándar y ediciones de equipos de desarrollo. La novedad será Visual Studio 2008 Shell, de carácter gratuito, que permitirá crear lenguajes y herramientas de desarrollo más verticalizadas.

Daniel comenta también que bajo Windows Vista, VS2008 será espectacular, e incluirá mejoras para la depuración de múltiples hilos. Ya no hay excusa para quedarnos con WXP ;-P

2. Compatibilidad hacia atrás
.NET framework 3.5 continúa la línea iniciada por Fx3.0 en cuanto al mantenimiento del CLR. Por tanto, y dado que lo único que hace es añadir ensamblados a las librerías presentes con las versiones 2.0 y 3.0 del framework, las aplicaciones actuales no se verán afectadas. Eso sí, necesitará los Service Packs 1 de ambas plataformas.

3. Generación multiplataforma
Visual Studio 2008 incluye la capacidad de crear proyectos para múltiples plataformas .NET, es decir, la 2.0, 3.0 y 3.5, desde el mismo entorno. Por tanto, no será necesario tener VS2005 instalado para generar ensamblados para .NET 2.0.

4. Multitud de novedades en C# 3.0 y VB9
Propiedades automáticas, delegados "relajados", inicializadores de objetos, inferencia de tipos, tipos anónimos, métodos de extensión, funciones lambda y métodos parciales, entre otros.

Pero no sólo eso... dado el punto 3 (generación multiplataforma), podremos usar estas nuevas características de nuestros lenguajes favoritos y generar para .NET 2.0.

5. LINQ
Se trata de una de las grandes revoluciones que nos aportará este nuevo conjunto de herramientas. Language INtegrated Query es un nuevo método de acceso a datos totalmente integrado en nuestro lenguaje habitual y de una forma muy independiente de la fuente de donde provengan (colecciones, XML, motores de bases de datos, etc.).

6. Novedades para ASP.NET
Visual Studio, así como el nuevo framework, ya incluirán ASP.NET AJAX de serie, así como 3 nuevos controles (ListView, DataPager y LinqDataSource). Además, el IDE ha sido muy mejorado e incluye soporte para intellisense y depuración de Javascripts, ¡también para ASP.NET 2.0!, y un nuevo diseñador que permite anidar páginas maestras.

7. Para el desarrollo en cliente
VS2008 incluirá nuevas plantillas de proyectos, así como un diseñador para WPF integrado con soporte para la comunicación WPF-WinForms. También se ha añadido el soporte para Firefox de la tecnología ClickOnce y XBAP (XAML Browser Applications).

8. Para el desarrollador de Office
Se ofrece soporte total para la personalizaciones (customisations) de Office 2007, así como para las plantillas de Office 2003.

9. Para desarrollo en servidor
Se han incluido nuevas plantillas para WCF y WF, y se han introducido mejoras interesantes en el primero, como el modelo de programación HTTP (sin SOAP) o serialización JSON.

10. Para el desarrollo en dispositivos móviles
Hay decenas de nuevas características, como el soporte para las versiones compactas de LINQ y WPF, o, a nivel de IDE, Unit Testing for Devices.

11. (punto extra) Código del framework
Pues sí, como ya es sabido, podremos depurar nuestras aplicaciones siguiendo el rastro por el interior de las clases y métodos del framework (como si no tuviéramos suficiente con las nuestras ;-)).

Más información en la fuente: The Moth.
lunes, 5 de noviembre de 2007
A raíz de un post anterior sobre scripts de arranque, y sobre todo en la relativa a la compartición del evento OnLoad por varios controladores, me ha llegado por varias vías la siguiente duda: ¿cómo se pueden vincular a este evento llamadas a funciones que incluyan parámetros?

Concretamente, gerardo pregunta cómo podría añadir varios controladores con parámetros al evento OnLoad de la página, como él mismo dice,

La funcion de script que usas para añadir varias funciones al evento onload esta bien si son llamadas sin parametros. La duda es cómo podría hacer lo mismo si la función que tiene que correr en el inicio recibiera un parametro de entrada.Siguiendo tu ejemplo, me gustaria usar algo como:

addOnLoad(init1(3));
addOnLoad(init2(4));


Efectivamente, la fórmula que propone este amigo no es válida; de hecho, estaríamos añadiendo al evento OnLoad el retorno de la llamada a init1(3), lo cual sólo funcionaría si esta función devolviera una referencia a una función capaz de ser invocada por el sistema.

Para hacerlo de forma correcta, como casi siempre en este mundo, hay varias formas. Comentaré algunas de ellas.

La obvia

Ni que decir tiene que el método más sencillo es sin duda introducir las llamadas en el atributo onload del elemento body de la página, es decir,

<body onload="alert('hola 1'); alert('hola 2');">
 
Por desgracia no siempre es posible modificar el atributo onload del cuerpo de la página, así que lo mejor será estudiar otras maneras.

La fácil

También podríamos utilizar un modelo bastante parecido al indicado en el post inicial, vinculando al OnLoad una función que, a su vez, llamará a las distintas funciones (con los parámetros oportunos) de forma secuencial:

// Asociamos las funciones al
// evento OnLoad:
addOnLoad(miFuncion1);
addOnLoad(miFuncion2);

function miFuncion1() {
alert('hola 11');
alert('hola 12');
}
function miFuncion2() {
alert('hola 2');
}
 

La "pro"

Aunque cualquiera de los dos métodos comentados hasta el momento son válidos y funcionan perfectamente, vamos a ver otra en la que se utiliza una característica de javascript (y otros lenguajes, of course), las funciones anónimas.

Las funciones anónimas son como las de toda la vida, pero con un detalle que la diferencia de éstas: no tienen nombre. Se definen sus parámetros y su cuerpo de forma directa en un contexto en el que pueden ser utilizados sin necesidad de indicar qué nombre vamos a darle.

En el caso que nos ocupa, y tomando como base el ejemplo anterior, en vez de invocar a la función addOnLoad() pasándole como parámetro el nombre de la función que contiene lo que queremos hacer, le enviaríamos una función anónima indicando exactamente lo que queremos hacer:

// En este código se hace lo mismo que
// el ejemplo anterior:

addOnLoad(
function() {
alert('hola 11');
alert('hola 12');
}
);
addOnLoad( function() { alert('hola 2'); } );
 
De esta forma la llamada a la función addOnLoad se realiza utilizando como parámetro la referencia a la función anónima, y todo puede funcionar correctamente.
viernes, 2 de noviembre de 2007
Unas semanas atrás escribía una entrada sobre Nifty Corners Cube, una librería javascript que permitía redondear las esquinas de los elementos de bloque de una web (como divs, h, etc.) sin necesidad de crear imágenes o hacer malabarismos con el marcado, sólo añadiendo unas referencias al archivo .js y algunos scripts básicos de inicialización.

Sin embargo, para un desarrollador habituado a arrastar y soltar, estas dos simples operaciones suponen demasiado esfuerzo como para considerar el uso de esta librería ;-), de ahí que me decidiera a crear NiftyDotNet.

NiftyDotNet es un componente para ASP.NET, escrito en C#, que encapsula todos los archivos y lógica necesarios para hacer funcionar Nifty Corners Cube en nuestras webs de una forma aún más fácil, simplemente arrastrando y soltando el control sobre nuestros webforms y ajustando unos sencillos parámetros, como el tamaño del borde o la selección de elementos a los que afectará.

Para que quede más claro, ahí va un ejemplo: observamos un formulario web en tiempo de diseño con un div central (que tiene un id='box1') y un control Nifty que afecta al mismo. A la derecha podemos ver también las distintas opciones de parametrización del control (puedes hacer clic sobre la imagen para ampliarla un poco):



Y continuación una captura con la página en tiempo de ejecución:



Como se puede ver, las esquinas del div central han sido redondeadas por el componente sin usar imágenes externas, sólo javascript no intrusivo. Increíble, ¿no? ;-)

El proyecto, publicado bajo GPL, se distribuye en tres paquetes, a elegir según el gusto y pretensiones del usuario:
  • Un ensamblado listo para ser utilizado en nuestros proyectos, o para añadirlo a la caja de herramientas (Toolbox) del entorno de desarrollo.
  • Una web de demostración, en la que podéis haceros una idea de la utilidad del componente. No hay una demo on-line debido a que en los servidores donde se encuentra no existe esta posibilidad, cuando encuentre un alojamiento apropiado la pondré para que pueda verse en vivo y en directo.
  • La solución VS2005 con el código fuente completo de ambos.

En la actualidad hay ya una versión bastante estable y depurada (a falta de comentarios de usuarios, claro!). Además, ha sido testeada tanto con Microsoft .Net Framework como con Mono, lo cual es siempre una buena noticia.

Por supuesto estaré encantado de recibir vuestras aportaciones, sugerencias, colaboraciones o comentarios de cualquier tipo.



Enlaces:
domingo, 28 de octubre de 2007
Inicializaciones de librerías, llamadas a servidor mediante Ajax para obtener datos o porciones de la página, efectos gráficos... son sólo algunos de los escenarios donde resulta interesante utilizar scripts de arranque o (startup scripts), que se ejecuten en cliente en cuanto le llegue la página web.

Esto hay al menos dos formas de hacerlo: llamar a la función deseada desde el evento onload() del cuerpo de la página o bien hacerlo en un bloque de scripts fuera de cualquier función, bien sea dentro del propio (X)HTML o bien en un recurso .js externo. Pero hace tiempo que tenía una curiosidad: ¿qué diferencia hay entre una u otra? ¿cuándo deben usarse? ¿tienen contraindicaciones?

Para averiguarlo, he creado la siguiente página:

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Prueba de scripting</title>
</head>
<body onload="alert('OnLoad()');">
<h1>Prueba Scripting</h1>
</body>
<script type="text/javascript">
alert('Script en HTML');
</script>
<script type="text/javascript" src="script.js"></script>
</html>


Como se puede observar:
  • en el elemento <body> he incluido un atributo onload="alert('onload');".
  • he añadido un bloque script con una única instrucción alert('script HTML');
  • he añadido también una referencia a un archivo script externo, en el que sólo hay una instrucción alert('archivo .js');
Además he jugado un poco con el orden de introducción de los bloques de scripts para comprobar su influencia en el orden de ejecución del código que contienen. El resultado ha sido el siguiente:
  • Se ejecuta en primer lugar el código incluido en los bloques <script> .
  • Si hay varios bloques de script, se ejecuta el código incluido en cada uno de ellos, siguiendo del orden en el que están declarados.
  • No importa si son scripts incrustados en la página o si se encuentran en un archivo .js externo, se ejecutan cuando le llega el turno según el orden en el que han sido definidos en la página, es decir, la posición del tag <script> correspondiente.
  • Por último, se ejecuta el código del evento onload del cuerpo de la página. De hecho, este evento se ejecuta una vez se ha cargado y mostrado la página al usuario, es el último en tomar el control.
Con estos datos, ya se puede intuir en qué casos puede ser conveniente usar un modelo u otro.

Debemos usar onload() si queremos que nuestro código se ejecute al final, cuando podemos asegurar que todo lo que tenía que pasar ya ha pasado; eso sí, mucho ojo, que onload() es un recurso limitado (de hecho, sólo hay uno ;-)), y si no se tiene cuidado podemos hacer que una asignación nuestra haga que no se ejecute la función anteriormente definida para el evento. Esto se evita normalmente incluyendo en el atributo onload de la etiqueda body las sucesivas llamadas a las distintas funciones de inicialización requeridas (<body onload="init1(); init2();"...), o bien desde script utilizando el siguiente código, todo un clásico:

function addOnLoad(nuevoOnLoad) {
var prevOnload = window.onload;
if (typeof window.onload != 'function') {
window.onload = nuevoOnLoad;
}
else {
window.onload = function() {
prevOnload();
nuevoOnLoad();
}
}
}

// Las siguientes llamadas enlazan las
// funciones init1() e init2() al evento
// OnLoad:

addOnLoad(init1);
addOnLoad(init2);

 

En cambio, la introducción de código de inicialización directamente en scripts se ejecutará al principio, incluso antes de renderizar el contenido de la página en el navegador, por lo que es bastante apropiada para realizar modificaciones del propio marcado (por ejemplo a través del DOM) o realizar operaciones muy independientes del estado de carga de la página. Como ventaja adicional, destacar su facilidad para convivir con otros scripts similares o asociados al evento OnLoad().
jueves, 25 de octubre de 2007
Comprobar si una variable de tipo string está vacía es una tarea que seguro realizamos muy a menudo en nuestras aplicaciones. Observando código, tanto propio como ajeno, he visto que existen varias formas de hacerlo, y a veces cometemos errores que pueden ser fácilmente evitables prestando un poco de atención.

Por ejemplo, dada una variable str declarada como string, utilizando en C# la expresión str.Equals("") podemos conocer si str contiene una cadena vacía. Sin embargo, si str contiene un valor nulo (lo cual es perfectamente posible al tratarse de un tipo referencia) se provocará una excepción de tipo System.NullReferenceException, puesto que estamos intentando llamar a un método de un objeto inexistente.

Ocurre lo mismo si intentamos averiguar el número de caracteres que contiene: (str.Length==0) es cierto si la cadena está vacía, pero igualmente revienta si se trata de un valor nulo.

Una posible solución es preguntar previamente si la cadena es nula y sólo en caso contrario preguntar, siguiendo alguno de los dos patrones descritos anteriormente, si se trata de un string vacío, algo así:
((str!=null) && (str.Length==0))
.

Como podéis observar, aunque válido, parece demasiado laborioso para los que tenemos prisa. Otra forma más corta e ingeniosa de poner lo mismo sería la siguiente: "".Equals(str). Como podéis ver, el problema del nulo desaparece, puesto que se llama al método Equals de la cadena constante "" que siempre tiene valor (la cadena vacía).

Sin embargo, cualquiera de los casos anteriormente citados pueden no funcionar correctamente si consideramos los nulos como una forma más de expresar una cadena vacía. Por ejemplo, observad el siguiente código:

private string saludar(string nombre)
{
if ("".Equals(nombre))
return "No saludo a nadie";
else
return "Hola, " + nombre;
}
 

La función retorna el literal "No saludo a nadie" cuando le llega un nombre vacío (""). Sin embargo, si le llega un valor nulo no se cumple la primera igualdad, entraría en el bloque else y retornaría un saludo absurdo, "Hola, ". Y es que hay veces donde semánticamente el nulo y la cadena vacía son idénticos.

Para estos casos es conveniente hacer equivalentes ambos valores, de forma que nuestra función se comporte exactamente igual tanto si recibe un nulo como si le llega un string vacío. Veamos algunas formas de conseguirlo.

Una fórmula que he visto alguna vez consiste en sumar a nuestro string una cadena vacía en algún momento del proceso, es decir, usar algo como: ""+str. Esta expresión devolverá siempre un string vacío o con el valor original de la variable str, pero nunca un nulo. Una vez realizada esta operación, podemos hacer la comparación con .Equals("") o .Length==0, aunque se recomienda este último por su mejor rendimiento.

Otra forma, algo mejor que la anterior, es usar dos comparaciones combinadas con OR: ((str == null) || (str.Equals(String.Empty))). Así, si str es nulo la expresión evalúa a cierto y sólo en caso contrario se realizará la comparación con la cadena vacía (String.Empty es lo mismo que el string "").

Pero sin duda la mejor opción sería usar el método estático introducido en la clase string en la versión 2.0 de la plataforma: string.IsNullOrEmpty(). Siguiendo con el ejemplo anterior, podríamos reescribirlo de la siguiente manera, consiguiendo el efecto deseado:

private string saludar(string nombre)
{
if (string.IsNullOrEmpty(nombre))
return "No saludo a nadie";
else
return "Hola, " + nombre;
}
 
Este sería un buen momento para dar por finalizado el post si no fuera por que existe un inconveniente a este método, algo que puede parecer increíble: en el framework de Microsoft IsNullOrEmpty() puede hacer que tu aplicación reviente en tiempo de ejecución en las versiones de producción (release) de los ensamblados debido a una mala optimización del JIT cuando utilizamos este método dentro de un bucle. No daré más detalles pues hay multitud de páginas hablando del problema (como VTortola, o El Bruno), pero aquí se aconsejan alternativas a utilizar. En fin, que este método, según se lee, debe ser usado con precaución, o incluso evitado si lo pensamos incluir en un bucle.

Llegados a este punto, por tanto, lo aconsejable es quedarnos con fórmulas artesanales como ((str == null)||(str.Length==0), hasta que IsNullOrEmpty esté en condiciones de ser utilizado, podemos suponer que en la próxima versión de la plataforma.

No he comprobado si existe el mismo problema sobre la plataforma Mono, pero dado que son implementaciones distintas lo más probable es que no ocurra, por lo que IsNullOrEmpty podría ser utilizado sin causar dolores de cabeza. A ver si un día tengo un ratillo y lo compruebo.

Hay que ver lo que da de sí una cosa tan simple, ¿eh?