November 2010 - Artículos

Muy buenas!

Una de las preguntas que mucha gente se formula cuando empieza a hacer cosillas con ajax y jQuery es ¿Como enviar datos codificados en JSON usando POST?

La verdad es que es muy sencillo, aunque jQuery no proporciona ninguna función por defecto que haga esto. Vamos a ver tres aproximaciones, las dos primeras incorrectas pero que nos acercarán para llegar al final a la una forma correcta de hacerlo.

Aproximación 1: Usando $.post

jQuery tiene una función específica para enviar datos usando post, llamada $.post. Así podriamos pensar que el siguiente método funcionaria:

function JsonPost(data, url, handler)
{
$.post(url, data, handler);
}

Y luego podríamos llamarlo de la siguiente manera:

// Envia un objeto con propiedades Col y Row a /Map/ViewPort y
// llama a fillMap con el resultado devuelto
JsonPost({ Col: c, Row: r}, "/Map/Viewport", function(data) {
fillMap(data);
});

Pero eso no realiza una petición JSON. Si usamos, p.ej. Firebug para analizar la petición vemos que lo que se envía al controlador es:

image

Si os fijáis los datos no están codificados en JSON, sinó en el formato “estándard” (param=value&param=value&…)

Si se lee la documentación de $.post() se ve que acepta un último parámetro datatype, así que podríamos pensar que poniendo dicho parámetro a “json” funcionará, pero no. El parámetro “datatype” indica el tipo de datos esperado de vuelta, no el que se envia.

Resumiendo: $.post() siempre envía los datos en el formato tradicional.

Aproximación 2: Usando $.post() y convertir los datos a Json

De acuerdo, hemos visto que $.post() nos transforma nuestro objeto javascript en la cadena tradicional de param=value&param=value&… Pero si a $.post() se le pasa una cadena la manda tal cual, por lo que si transformamos el objeto javascript a una cadena JSON parece que todo funcionará.

Para transformar un objeto javascript a notación JSON podemos usar el plugin jQuery-Json. Puede haber otros plugins por ahí, pero uséis el que uséis, aseguraros que soporta native json. Native json es una funcionalidad que los nuevos navegadores traen y que se basa en un método llamado JSON.stringify que transforma el objeto pasado a una cadena json. Evidentemente siempre será mucho más rápido si el propio navegador puede hacer esto de forma nativa que si es código javascript que construye la cadena. El plugin jQuery-json usa JSON.stringify si está disponible y sólo en caso de que no exista usa código javascript.

Así pues podríamos modificar nuestra JsonPost para que quede como:

function JsonPost(data, url, handler)
{
$.post(url,$.toJSON(data), handler);
}

El método $.toJSON es el método proporcionado por el plugin. Ahora sí que estamos usando JSON para enviar los datos:

image

Ok. Un parentesis: Recordad que MVC2 no tiene soporte directo para realizar binding de datos enviados en JSON. Aunque es muy fácil crearse un Value Provider propio que de soporte a JSON en MVC2. Y recordad que MVC3 ya viene con el soporte por defecto de JSON.

Bien, si usáis un value provider para JSON que os hayais encontrado por “ahí afuera” lo más probable es que no os funcione, es decir que en el controlador no recibáis los datos. Por que? Pues por lo que está marcado en rojo en la imagen antrior: aunque estamos enviando los datos en formato json, el content-type no es correcto. El content-type de JSON es application/json y este es el content-type que suelen mirar los value providers de JSON.

Aproximación 3: Usando $.ajax()

Bien, ya que $.post() no permite especificar el content-type, la tercera y última aproximación es usar $.ajax(), que es la función más personalizable que tiene jQuery para hacer peticiones ajax.

De hecho básicamente lo único que tenemos que cambiar respecto la aproximación anterior es el content-type:

function JsonPost(data, url, handler)
{
$.ajax(
{
url: url,
type: "POST",
success: handler,
data: $.toJSON(data),
contentType: "application/json"
});
}

Y lo que nos muestra Firebug de la petición:

image

Fijaos que ahora el propio Firebug reconoce que la petición es en JSON y me muestra los datos en JSON.

Espero que os sea útil!

Un saludo!

con 1 comment(s)
Archivado en:

Muy buenas!

El jueves 2 de diciembre voy a realizar un WebCast para la gente del Lleida DotNetClub sobre ASP.NET MVC.

La idea es empezar desde cero a desarrollar una aplicación ASP.NET MVC y ver hasta donde llegamos. Iremos explorando el framework y viendo paso a paso sus características: controladores, vistas, modelos, vistas parciales, ajax, helpers, inyección de dependencias,…

La idea es que sea 100% Visual Studio, nada de powerpoints que de esto ya se encuentra mucho en la web!

La página de registro está en https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032471331&EventCategory=4&culture=es-ES&CountryCode=ES

Así que si estás interesado en ver ASP.NET MVC, ya sabes: te esperamos! ;-)

Saludos y gracias a la gente del Lleida DotNetClub por invitarme a dar la charla! :)

PD: Huelga decir que si tienes cualquier comentario sobre algo específico que te gustaría ver en este Webcast coméntalo por aquí y voy a ver como se puede encajar! De lo que se trata es que este Webcast sea interesante para vosotros!

con 6 comment(s)
Archivado en: ,

Muy buenas! Hacía tiempo que no escribía nada de la serie C# Básico. En esta serie voy tratando temas (sin ningún orden en particular) que considero que son fundamentos más o menos elementales del lenguaje. No es un tutorial al uso, cada post es independiente del resto y como digo no están ordenados por nada en particular.

El post de hoy nace a raíz de una pregunta que vi en los foros de msdn (http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/daf808ed-a0aa-4e1e-88ed-64ee60cce918), donde un usuario preguntaba porque el intentar convertir una List<LogVehiculos> a List<Log> le daba error teniendo en cuenta que LogVehiculos derivaba de Log.

Mi respuesta fue que en C# 3.5 los genéricos no son covariantes, y este post es para explicarlo todo un poco más :)

Antes que nada, covarianza y contravarianza son dos palabrejas muy molonas para explicar dos conceptos que son muy básicos pero que tienen implicaciones muy profundas. El mejor artículo en español que he leído sobre covarianza y contravarianza es el del Doctor (maestros hay algunos, doctores muchos menos) Miguel Katrib que salió publicado en la DotNetMania número 62 y titulado “La danza de las varianzas”. Es un artículo que debe leerse con atención pero sin duda de lo mejorcito que he leído nunca. Este post no entrará ni mucho menos en la profundidad de dicho artículo, así que si os interesa el tema, ya sabeis: haceros con dicha DotNetMania.

En este post nos vamos a centrar sólamente en la covarianza.

Covarianza

Llamamos covarianza a algo muy simple: Cuando permitimos sustituir un tipo D por otro tipo B. Para que eso sea posible debe cumplirse una condición: Que no haya nada que pueda hacerse con B y NO pueda hacerse con D.

Vamos a suponer que tenemos una clase Animal, de la cual deriva la clase Perro:

class Animal
{
public void Comer() { ... }
public void Dormir() { ... }
}

class Perro : Animal
{
public void VigilarCasa() { ... }
}

Si tenemos un método cualquiera que devuelva un perro, nosotros podemos convertir el resultado a un animal:

Perro ComprarPerro() { ... }
// entonces eso es válido:
Animal animal = ComprarPerro();

Eso es covarianza: el poder sustituir la clase derivada (Perro) que devuelve el método con la clase base (Animal). C# soporta covarianza entre una clase derivada y su clase base (como hacen de hecho todos los lenguajes orientados a objetos).

Tiene lógica, porque fijaos que no hay nada que pueda hacerse con un Animal (B) que no pueda hacerse con un Perro (D): Dado que Perro deriva de Animal hereda todos sus métodos y propiedades.

Pero la covarianza se da también en más casos y algunos de ellos están soportados en C#. Veamos…

Covarianza en delegados

Se trata de poder asignar a un delegado que devuelve un Animal un método que devuelve un Perro:

delegate Animal AnimalDelegate();
class Program
{
static Perro ObtenerPerro() { return new Perro(); }
static Animal ObtenerAnimal() { return new Animal(); }
static void Main(string[] args)
{
Animal animal = ObtenerPerro();
AnimalDelegate ad = new AnimalDelegate(ObtenerAnimal);
AnimalDelegate ad2 = new AnimalDelegate(ObtenerPerro);
}
}

Fijaos en la segunda declaración (ad2): Aunque el delegate está declarado para métodos que devuelven un Animal podemos usar este delegate con métodos que devuelvan un Perro. Por eso decimos que los delegates son covariantes en C#.

Covarianza en arrays

El siguiente código en C# funciona y es totalmente válido:

Animal[] animales = new Perro[100];

Es decir podemos asignar un array de Perros a un array de Animales. De nuevo los arrays son covariantes en C#. Esta decisión se tomó en su día para, bueno… luego hablaremos más sobre ella :)

Covarianza en genéricos

El siguiente código no compila en C#:

// error CS0029: Cannot implicitly convert type 'System.Collections.Generic.List<ConsoleApplication8.Perro>' to 'System.Collections.Generic.List<ConsoleApplication8.Animal>'
List<Animal> animales = new List<Perro>();

Es por ello que decimos que los genéricos NO son covariantes en C#.

Y ahora viene la pregunta… ¿por que?

Bien, recordad que si yo quiero sustituir un tipo D por otro tipo B eso significa que en un objeto de tipo D debo poder hacer cualquier cosa que haga en un objeto de tipo B. Es decir, si hay algo, llamémosle f(), que pueda hacer para un objeto de tipo B que no pueda hacer con un objeto de tipo D, no puedo aplicar covarianza… Ya que entonces podría hacer D.f() que no sería válido (recordad que f() es válido para B y no para D).

Cojamos el caso de List<Animal> y List<Perro> (recordad que Perro deriva de Animal). La pregunta es… hay alqo que podemos hacer con List<Animal> y que NO podamos hacer con List<Perro>? Veamos…

  • Con List<Animal> puedo contar cuantos animales hay. Con List<Perro> también.
  • Con List<Animal> puedo obtener todos los Animales que hay. Con List<Perro> puedo obtener los Perros, pero dado que Perro deriva de Animal, si obtengo un Perro estoy obteniendo un Animal (primer ejemplo que hemos visto). Así pues ningún problema.
  • Con List<Animal> puedo añadir un Animal. Con List<Perro> puedo añadir… un Perro. Ojo que eso es importante: A List<Animal> puedo añadirle cualquier Animal… puede ser un Perro, puede ser un Gato. A List<Perro> no puedo añadirle cualquier animal, debe ser un Perro forzosamente.

Por lo tanto ya hemos encontrado que se puede hacer con List<Animal> que no pueda hacerse con List<Perro>: Añadir un Gato.

Si C# nos dejara aplicar covarianza entonces eso sería válido:

List<Animal> animales = new List<Perro>();
animales.Add(new Gato()); // EEehhh... estoy añadiendo un Gato a una lista de Perros?

Por lo tanto, para evitar eso y asegurar que las listas de perros sólo tendrán perros el compilador no nos deja hacer esa conversión: Los genéricos no son covariantes.

Y los arrays? Recordáis que los arrays sí son covariantes. El siguiente código es válido y legal:

Animal[] animal = new Perro[100];
animal[0] = new Gato(); // Un Gato en una jauría de Perros!

Si ejecutas el siguiente código obtendrás una ArrayTypeMismatchException en tiempo de ejecución. Es decir el código compila pero luego rebienta.

Alguien podría decir que hubiesen aplicado eso mismo a las Listas… dejar que fuesen covariantes y luego rebentar en tiempo de ejecución si añado un Gato a una List<Perro>. Porque no lo han hecho así? Pues porque repetir errores no es nunca una buena solución. Los arrays jamás debieron haber sido covariantes. Si los crearon así fue para dar soporte a lenguajes tipo Java dentro del CLR (Java tiene arrays covariantes). Y así estamos: un error de diseño de Java propagado a .NET. Fijaos que eso obliga a que cada vez que añadimos un elemento en un array el CLR en tiempo de ejecución deba comprobar que el elemento realmente es del tipo del array. Viva la eficiencia!

Y con todo eso… llegó el Framework 4

Bien… Ahora analicemos el siguiente código:

static IEnumerable<Perro> JauriaDePerros()
{
return new List<Perro>();
}
static void Main(string[] args)
{
IEnumerable<Animal> perritos = JauriaDePerros();
}

Ya os lo avanzo: el siguiente código no compila con el Framework 3.5. Recordad: los genéricos no son covariantes y hemos visto la razón. Pero tiene sentido en este caso? Hay algo que pueda hacer con un IEnumerable<Animal> y que no pueda hacer con IEnumerable<Perro>? Veamos…

  1. Con un IEnumerable<Animal> puedo obtener todos los Animales. Con un IEnumerable<Perro> puedo obtener todos los Perros, pero como hemos visto ya, los Perros los puedo ver como Animales.

Y ya está. No puedo hacer nada más con un IEnumerable<> salvo obtener sus elementos. Entonces porque no compila el código en C#? Pues bien, porque pagan justos por pecadores: En el framework 3.5 los genéricos no son covariantes. Nunca, aunque por lógica pudiesen serlo.

Para tener una solución a estos casos donde la covarianza tiene sentido, debemos usar el Framework 4 (VS2010). Una de las novedades que incorpora C# en esta versión es precisamente esta: covarianza de genéricos en según que casos.

Veamos: la covarianza en genéricos es segura cuando el parámetro genérico se usa sólamente de salida. Es decir cuando ningún método acepta ningún parámetro del tipo genérico, como mucho sólo lo devuelven. El problema en el caso de List<> estaba en que podía añadir un Gato a una lista de Perros. Y eso es posible porque uno de los métodos de la clase List<T> es Add(T item). Es decir el tipo genérico se usa como valor de entrada a los métodos. En cambio con IEnumerable<T> hemos visto que no hay ningún problema: En un IEnumerable<T> sólo puedo obtener sus elementos, pero no puedo añadirle elementos nuevos. No hay ningún método que reciba un parámetro del tipo genérico. Como mucho hay métodos que devuelven ojetos del tipo genérico. En este caso la covarianza es segura.

Para indicar en C# 4.0 que una clase genérica es covariante respecto a su tipo genérico, usamos la palabra clave out. P.ej. IEnumerable<T> en C# 4.0 está definido como:

public interface IEnumerable<out T> : IEnumerable
{
// Métodos...
}

Fijaos en el uso de out para indicarle al compilador: Este tipo es covariante respecto al tipo genérico T. Entonces este código que en VS2008 no compilaba, es válido en C# 4.0:

static IEnumerable<Perro> JauriaDePerros()
{
return new List<Perro>();
}
static void Main(string[] args)
{
IEnumerable<Animal> perritos = JauriaDePerros();
}

Por supuesto, esto sigue sin compilar:

static List<Perro> JauriaDePerros()
{
return new List<Perro>();
}
static void Main(string[] args)
{
List<Animal> perritos = JauriaDePerros();
}

Ya que List<T> no es covariante respecto al tipo genérico T (lógico, si lo fuese podría añadir un Gato a una lista de Perros).

En cambio eso si que es correcto en VS2010:

static List<Perro> JauriaDePerros()
{
return new List<Perro>();
}
static void Main(string[] args)
{
IEnumerable<Animal> perritos = JauriaDePerros();
}

Aunque el método JauriaDePerros() devuelve una List<Perro>, el código funciona porque:

  1. List<T> implementa IEnumerable<T>
  2. IEnumerable<T> es covariante respecto a T

En el fondo, fijaos que no hay problema: con perritos lo único que puede hacerse es obtener sus elementos, así que de nuevo no hay peligro de que añada un Gato a perritos.

Declaración de mis clases genéricas covariantes

Si yo creo una clase que quiera que sea covariante con su tipo genérico, simplemente debo usar out. La única restricción es que ningún método de mi clase podrá aceptar un parámetro del tipo genérico:

interface Foo<out T>
{
T Bar() { ... }
void Baz(T t) { ... }
}

Este código no compila (error CS1961: Invalid variance: The type parameter 'T' must be contravariantly valid on 'ConsoleApplication5.Foo<T>.Baz(T)'. 'T' is covariant.). Ese mensaje de error largote lo único que quiere decir es que T es covariante, y por lo tanto no podemos aceptar parámetros de tipo T.

Finalmente tened presente que sólo las interfaces pueden declarar que su tipo genérico es covariante (las clases no).

Bueno… dejémoslo aquí. Hay otro termino ligado a la covarianza que es la contravarianza, aunque no es tan común como la covarianza y quizá algún día hablemos de ella :)

Un saludo y recordaros lo que digo siempre en los posts de esta serie: Si tenéis temas sobre el lenguaje C# que queráis tratar, hacédmelo saber y haré lo que pueda!!!

con 13 comment(s)
Archivado en: ,

Buenas! En el post anterior os comenté el soporte de Unobtrusive Ajax en ASP.NET MVC3. Hoy quiero mostraros que esa técnica ni es exclusiva de MVC3, ni  requiere HTML5 para nada. En fin, que podéis empezar a usarla ya, con independencia de la tecnología que uséis. Lo que contaré en este artículo no es nada “revolucionario” ni una “técnica nueva”…

De hecho, el ejemplo va a ser una página HTML, nada de ASP.NET :)

Veamos, la técnica de Unobtrusive Javascript, se refiere a no tener mezclado código javascript con código de marcado HTML. Es decir, no queremos algo como:

<input type="text" id="txtName" onkeypress="checkKey();" />

Aquí estamos mezclando código HTML con el código javascript (la llamada checkKey en el onkeypress).

Imaginemos que queremos que nuestros textboxes sólo acepten números. Y recordad que el objetivo es no tener código javascript mezclado con nuestro código HTML.

Eso lo podemos conseguir fácilmente, ya con jQuery:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Demo Unobtrusive Javascript</title>
<script src="jquery-1.4.1.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
$(document).ready(function () {
$('input:text').keypress(function (event) {
if (event.keyCode < 47 || event.keyCode > 58) {
event.preventDefault();
}
});
});
</script>

Introduce sólo números: <br />
<input type="text" />
</body>
</html>

Incluso, si no queréis que haya el tag <script> con todo el código, podemos moverlo a un .js separado y usarlo desde nuestra página HTML que entonces quedaría como:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Demo Unobtrusive Javascript</title>
<script src="jquery-1.4.1.js" type="text/javascript"></script>
<script src="myscript.js" type="text/javascript"></script>
</head>
<body>
Introduce sólo números: <br />
<input type="text" />
</body>
</html>

Por lo tanto vemos que con jQuery es muy fácil asignar comportamiento a objetos DOM, sin necesidad de andar con los handlers onXXXX.

Ahora bien, el código jQuery selecciona todos los <input type=”text”>, que passa si sólo quiero seleccionar algunos? Como le indico a mi código jQuery que sólo algunos textboxes son numéricos?

Una solución es invertarnos un atributo que indique que elementos queremos como numéricos. De esta manera p.ej. la página HTML queda como:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Demo Unobtrusive Javascript</title>
<script src="jquery-1.4.1.js" type="text/javascript"></script>
<script src="myscript.js" type="text/javascript"></script>
</head>
<body>
Introduce sólo números: <br />
<input type="text" datatype="numeric" /> <br />
Aquí puedes introducir lo que quieras: <br />
<input type="text" />
</body>
</html>

Fijaos en el “datatype=”numeric” que es el atributo que me va a servir para decidir que textboxes son numéricos.

Y el código de myscript.js queda como:

$(document).ready(function () {
$('input[datatype=numeric]').keypress(function (event) {
if (event.keyCode < 47 || event.keyCode > 58) {
event.preventDefault();
}
});
});

Y listos, simplemente incluyendo “myscript.js” en cualquier página ya podemos declarar que un textbox es numérico simplemente poniendo el atributo datatype=”numeric”.

Ahora, si alguien hace otra librería javascript para textboxes numéricos si también usa este atributo para indicarlos (ahí está el quid de la cuestión) simplemente cambiando el <script> para que en lugar de ir a myscript.js vaya a la nueva librería, ya tengo todo el cambio hecho… es decir, me he independizado del framework javascript que use.

Y por ahí por donde entra HTML5? Pues bien, como eso de crearnos nuestros propios atributos está bien pero genera HTML que podríamos llamar inválido (en el sentido de que estos atributos no forman parte de HTML), para HTML5 han decidido simplemente que todos estos atributos “inventados” empiecen por data-.

Lo “único” que dice al respecto HTML5 es: “Hey, si tienes que invertarte un atributo para lo que sea, haz que su nombre empiece por data-. Todos los atributos que empiecen por data- son atributos inventados por alquien y deben ser ignorados a todos los efectos (salvo para quien lo haya inventado que hará con él lo que le plazca, claro). Ok, también añade una API específica (element.dataset) para leer esos atributos (pero eso de momento no nos importa ya que no está soportada por la mayoría de navegadores).

Por lo tanto, si en lugar de que mi atributo se llame datatype, hago que le llame data-datatype (p.ej. cualquier nombre que empiece por data-) ya lo tengo todo HTML5 compliant!

De hecho podéis hacer la prueba en http://validator.w3.org/check. Entráis el código HTML de la página y lo validáis contra:

  • HTML5 usando el atributo datatype=”numeric” y os dará error (Attribute not allowed)
  • HTML5 usando el atributo data-datatype=”numeric” y os validará correctamente.
  • Cualquier otra versión de HTML y os dará error en ambos casos.

Y listos! Por lo tanto fijaos que desde ya podeis empezar a aplicar técnicas de “Unobtrusive Javascript”: no necesitáis HTML5 para nada, ni MVC3 ni nada y la recompensa es un HTML mucho más claro y sencillo de ver!

Mi opinión es que, gracias a que HTML5 ha definido un espacio de nombres (data-) para los atrbutos inventados empezaremos a ver, cada ves más, librerías de javascript que usarán esos atributos, y seguramente algunos de ellos terminarán siendo estándares de facto (si yo hago una librería de javascript para validación. pues intentaré usar los mismos atributos data- que use la librería que sea líder en aquel momento, para compatibilizarme con ella).

Por cierto, si vais a usar muchos atributos data- en vuestras páginas web, echadle un vistazo a este plugin de jQuery: HTML5 Dataset.

Un saludo!

Nota: El código de ese artículo lo he probado con IE9 y Firefox 3.6.10.

con 9 comment(s)
Archivado en:

Buenas! Una de las novedades más interesantes de MVC3 es el soporte para eso que se llama Unobtrusive Ajax. La verdad es que no encuentro una buena traducción para Unobtrusive (discreto no me convence).

La idea del Unobtrusive Ajax es evitar mezclar código script con código HTML. De la misma manera que CSS nos permite separar completamente el código HTML de su representación, con Unobtrusive Ajax vamos a poder separar el código javascript del código HTML.

Pero mejor, veamoslo con un ejemplo, ultra sencillo :)

Imaginad que tengo una vista con este contenido:

<h2>Normal Ajax</h2>
<% using (Ajax.BeginForm("PostData", new AjaxOptions() { HttpMethod="Post", UpdateTargetId="datadiv"})) { %>

<label for="name">Name: </label>
<input type="text" name="name" id="name"/>
<input type="submit" value="Send" />
<% } %>
<hr />
Aquí irá el resultado: <p />
<div id="datadiv">
</div>

Esta vista genera un <form> con un campo de texto y envía los datos a una acción llamada “PostData” e incrusta el resultado de dicha acción (que será una vista parcial) en el div cuyo id es “datadiv”.

Este es el código HTML generado por esta vista en MVC2:

<h2>Normal Ajax</h2>
<form action="/Home/PostData" method="post"
onclick="Sys.Mvc.AsyncForm.handleClick(this, new Sys.UI.DomEvent(event));"
onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace, httpMethod: &#39;Post&#39;, updateTargetId: &#39;datadiv&#39; });">
<label for="name">Name: </label>
<input type="text" name="name" id="name"/>
<input type="submit" value="Send" />
</form>
<hr />
Aquí irá el resultado: <p />
<div id="datadiv">
</div>

Fijaos en que en el tag <form> se le ha incrustado código javascript para gestionar el onclick y el onsubmit (para poder realizar el envío via ajax).

Bien… y esta misma vista (idéntica) que código genera en MVC3? Pues el siguiente:

<h2>Normal Ajax</h2>
<form action="/Home/PostData"
data-ajax="true" data-ajax-method="Post" data-ajax-mode="replace"
data-ajax-update="#datadiv" method="post">

<label for="name">Name: </label>
<input type="text" name="name" id="name"/>
<input type="submit" value="Send" />
</form>

<hr />
Aquí irá el resultado: <p />
<div id="datadiv">
</div>

Fijaos que diferencia… No hay nada de javascript mezclado en el código. Todo es HTML. Simplemente al tag <form> se le añaden unos cuantos atributos (los que empiezan por data-ajax) que indican como se debe comportarse este formulario a nivel de Ajax.

Y quien realiza “la magia”? Pues quien va a ser… nuestra amada jQuery, junto con una extensión de Microsoft (el fichero jquery.unobtrusive-ajax.js)! Para que esto funciona teneis que añadir tanto jQuery como la extensión de MS (yo los pongo en la master):

<script src="<%: Url.Content("~/Scripts/jquery-1.4.1.js") %>" type="text/javascript"></script>
<script src="<%: Url.Content("~/Scripts/jquery.unobtrusive-ajax.js") %>" type="text/javascript"></script>

Esta adaptación de los helpers en MVC3 para soportar esta característica es a lo que nos referimos cuando decimos que “ASP.NET MVC3 da soporte para Unobtrusive Ajax”, y es una doble gran noticia. Digo doble porque por un lado nos permite seguir usando los helpers con la garantía de que vamos a generar código “limpio” de javascript y por otro lado el helper de Ajax usa ¡por fin! jQuery. A diferencia de MVC2 donde el Helper Ajax usaba la Ajax Library de Microsoft. De hecho, aunque en los templates de proyecto se sigue poniendo, si me aceptas un consejo: bórrala y no la uses. Puedes borrarla con total tranquilidad porque en MVC3 ningún helper la usa.

Unobtrusive Ajax viene habilitado por defecto en los nuevos proyectos MVC3 pero lo podéis deshabilitar (y entonces generar el mismo código que en MVC2, usando la Microsoft Ajax Library). Podeis deshabilitarlo a nivel de vista o para todo el proyecto.

Para deshabilitarlo a nivel de vista, basta con incluir:

<% HtmlHelper.UnobtrusiveJavaScriptEnabled = false; %>

Para deshabilitarlo para todo el proyecto, puedes incluir ese mismo código en el global.asax.cs o bien usar web.config:

<configuration>
<appSettings>
<add key="UnobtrusiveJavaScriptEnabled" value="false"/>
</appSettings>
</configuration>

Lo mismo para habilitarlo. Si no aparece la entrada UnobtrusiveJavaScriptEnabled en el <appSettings> el valor por defecto es false. Es por eso que si haces un upgrade de un proyecto de MVC2 a MVC3, no tendrás esta entrada en el web.config y por eso Unobtrusive Ajax estará deshabilitado!

Un saludo!

PD: El hecho de que los atributos que se usan para que Unobtrusive Ajax funcione empiecen por “data-“ es porque HTML5 reserva estos atributos “para usos propios de los scripts del site”, tal y como podéis leer en la especificación de Custom Data Attributes.

con 5 comment(s)
Archivado en:

Ayer Lluis escribía este gran post: How to: Obtener controles de un formulario con generics. Como bien dice es una pregunta… recurrente en todos los sitios :)

Lo bueno de eso del desarrollo es que para todo hay varias soluciones, así que aquí os propongo otra, pero usando Linq. Personalmente me encanta Linq, supongo que es porqué siempre me han fascinado los lenguajes funcionales…

Antes que nada tenemos que solucionar un temilla: Linq funciona sobre IEnumerable<T> pero la propiedad Controls de un Control devuelve un objeto de tipo ControlCollection (otra de esas n-mil clases que no tienen sentido alguno y que existen sólo porque no teníamos generics en la versión 1 del framework). Así que el primer paso es obtener un IEnumerable<Control> a partir de una ControlCollection. Con un método extensor eso es trivial:

public static IEnumerable<Control> AsEnumerable (this Control.ControlCollection @this)
{
foreach (var control in @this) yield return (Control)control;
}

Ale… listos, con eso transformamos la CollectionControl en un IEnumerable<Control> y tenemos acceso a todo el potencial de Linq… Y como queda el método para obtener todos los controles de un tipo? Pues así:

public static IEnumerable<T> GetAllControls<T>(this Control @this) where T : Control
{
return @this.Controls.AsEnumerable().Where(x => x.GetType() == typeof(T)).
Select(y=>(T)y).
Union(@this.Controls.AsEnumerable().SelectMany(x => GetAllControls<T>(x)).
Select(y=>(T)y));
}

¡No me diréis que no es precioso: no hay bucles, no hay ifs… Os he dicho que me encanta Linq? ;-)

Hay una pequeña diferencia entre la versión de Lluís y esta mía: la versión de Lluís usa una List<Control> en la que añade todas las referencias (copia las referencias a la lista. Ojo: las referencias, no los controles). Esa versión que usa Linq, no copia las referencias en ningún sitio, sinó que simplemente itera sobre la coleccion original: no crea listas internas, ni nada… Ese es el poder de Linq!

Es cierto que al usar IEnumerable<T> como valor de retorno, perdemos el método ForEach() (puesto que IEnumerable<T> no lo tiene y Linq no lo proporciona), pero hacer un método ForEach es trivial:

public static void ForEach<T>(this IEnumerable<T> @this, Action<T> action)
{
foreach (T t in @this)
{
action(t);
}
}

De todos modos, si os preguntáis porque Linq no ofrece un método ForEach quizá deberíais leeros este post de Octavio: Observaciones con respecto a un método extensor ForEach<T>.

Un  saludo a todos y gracias a Lluís por darme “la excusa” de hacer otro post! ;-)

con 3 comment(s)
Archivado en:

Andamos todos revolucionados estos dias, a raíz de unas declaraciones de Bob Muglia donde decía “Our strategy with Silverlight has shifted”. Eso unido al énfasis que se dio a HTML5 en el keynote del PDC y la no mención en absoluto de nada referente a Silverlight han disparado los rumores.

Así pues… ¿está Silverlight muerto, agonizante o por el contrario está mejor que nunca? Primero un disclaimer: este es un post de opinión, todo lo que yo afirmo tajantemente en este post son cosas que yo creo. No tengo ni el conocimiento ni la razón absoluta, y además en MS nunca se sabe, así que como suele decirse: al final el tiempo dará y quitará razones :)

La estrategia inicial de Microsoft para posicionar Silverlight fue darle el nicho de aplicaciones web: Con Silverlight tus aplicaciones web tendrán una experiencia de usuario mejor, decían. En estos tiempos, comparar Silverlight con Flash era habitual, aunque Microsoft insistía en que no eran comparables: que Silverlight era para aplicaciones completas y no para pequeños adornos. Cuando hacía tiempo que Flash había asumido que no sustituiría a HTML, parecía ser que Silverlight quería asumir el relevo.

Pero con Silverlight 3 todo cambió: la posibilidad de ejecutar aplicaciones out-of-browser, la interoperabilidad COM y mejoras en el acceso a dispositivos locales, convertían a SL3 en algo distinto. Estaba claro que Silverlight llegaba a sitios donde HTML no sueña con llegar nunca. La batalla que inicialmente se libraba en el navegador ahora se trasladaba también al escritorio, y el rival era Adobe AIR. Habéis visto Seesmic Desktop 2? Es un excelente cliente de Twitter, para Windows y Mac, es una aplicación de escritorio… y está hecha con Silverlight.

¿Y donde estamos ahora?

El otro día en twitter conversaba con Alejandro Mezcua (@byteabyte) y Dani Mora (@LoDani) sobre el futuro de Silverlight. Yo argumentaba que no creo ni mucho menos que Silverlight esté muerto. De hecho le veo un gran futuro a Silverlight en aplicaciones de escritorio y en aplicaciones para Windows Phone 7 (bueno, aquí depende de como le vaya a WP7, claro). Pero no le veo futuro para aplicaciones web. Quiere decir esto que Silverlight va a desaparecer del browser? No, tiene su nicho en sites específicos donde HTML no llega: p. ej. nada mejor que Silverlight para streaming de video. Sí, sí… HTML5 va a soportar vídeo, pero no soportará DRM ni bitrates variables. Si necesitas esto, necesitarás algo externo que te lo de, y ahí entra Silverlight. Pero para la creación de aplicaciones web, no lo veo, y diría que Microsoft tampoco :)

¿Y RIA? La clave de RIA es lo que significa la I. Dani me comentaba que para él, la I de RIA era “aquel entorno que el administrador de sistemas podía controlar”. Entonces no estamos hablando de internet… llamésmole intranet o alguna otra cosa, pero no internet. Si quieres desarrollar una aplicación para internet no hay mejor opción que HTML. Y los tiempos han cambiado mucho: de acuerdo que hace tiempo desarrollar con javascript era poco menos que un infierno, pero ahora tenemos a jQuery que convierte eso en un juego de niños. Antes Ajax era doloroso y entraba con vaselina: ahora con un par de líneas puedes usar Ajax sin preocuparte de que navegadores se usan ni nada parecido. Y sí: hay jQuery para dispositivos móviles. Aunque de todos modos la experiencia parece demostrar que en los móviles la gente prefiere aplicaciones nativas antes que webs.

Así que si quieres estar presente en aplicaciones web dentro de poco tiempo, aprende ya HTML5. No hagas caso de los que dicen que no está terminado, que no saldrá hasta dentro de no se cuantos años: son verdades a medias. Es cierto que la especificación no está lista, pero muchas partes ya estan terminadas, y ya están siendo implementadas en los navegadores. No ha salido hace poco la noticia de que IE9 era el navegador más compatible con HTML5? Como podría ser si no hubiese salido nada de HTML5? Dentro de poco ya comenzaremos a ver sites desarrollados en HTML5. El momento de lanzarse no es dentro de un, dos o tres años: es ahora.

Pero seguiremos viendo Silverlight en el navegador? Pues creo que sí: en la gran internet en aquellos sitios junto a HTML, donde se requieran aspectos que HTML5 no va asumir y en intranets (o entornos controlados) también supongo que podrán verse… Aunque en estos entornos, porque obligar al usuario a usar un navegador? Las capacidades out of browser de Silverlight hacen que el usuario tenga la sensación de usar una aplicación nativa, con toda la seguridad del sandbox de Silverlight y la misma facilidad de actualización que si una aplicación web se tratara.

Y fuera del navegador? Pues sin duda. Veremos cada vez más aplicaciones de escritorio desarrolladas en Silverlight, y tener todas sus ventajas: actualizaciones automáticas, seguridad y multiplataforma (Windows, Mac). Y ojalá Microsoft se lance en serio a Linux y haga su implementación de Silverlight (y no lo deje medio abandonado con Moonlight).

De hecho, para resumir este post, si hay alguien que deba sentirse amenazado por Silverlight no es ni mucho menos HTML5… en todo caso, si hemos de buscar a alguien, se trataría de WPF. Cada versión de Silverlight acorta distancias con su hermano mayor y no es descabellado pensar si algún dia llegarán a unirse.

Y a vosotros que os parece?

Un saludo!

con 36 comment(s)
Archivado en: