ASP.NET MVC3: Validación remota

Muy buenas!

Una de las novedades que nos trae ASP.NET MVC3, con respecto a MVC2 es poder usar fácilmente la validación remota: eso es, desde cliente llamar a un método del servidor que nos diga si un dato (entrado p.ej. en un campo de texto es válido o no). Y cuando digo fácilmente me refiero a fácilmente, muy fácilmente.

Vamos a ver un ejemplo: para ello vamos a modificar la aplicación de ejemplo que crea MVC3 para que al darnos de alta, consulte si el usuario ya existe y si es el caso no nos deje. Os recuerdo que esa validación es Ajax, eso significa: el campo de texto pierda el foco se realizará la petición (en background) al servidor que comprobará si el usuario entrado ya existe y si es así mostrará un error en el campo de texto asociado.

Vamos pues, a verlo paso a paso 😉

1. Viendo que nos genera MVC3

Para empezar creamos un nuevo proyecto ASP.NET MVC3. Cuando os pida el template, usad el de Internet Application (no uséis el Empty). De esa manera MVC3 nos crea el esqueleto de la aplicación inicial:

image

El fichero AccountModels.cs tiene distintos Viewmodels que usan las acciones del controlador Account. La acción que da de alta un usuario es Register que está definida en el controlador Account:

[HttpPost]
public ActionResult Register(RegisterModel model)
{
// Código...
}

La acción usa la clase RegisterModel que es uno de los viewmodels definidos en AccountModels.cs:

public class RegisterModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }

[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string Email { get; set; }

[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }

[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}

2. Habilitando la validación remota

La validación remota en MVC3 se habilita, como el resto de validaciones, usando DataAnnotations, concretamente con el atributo Remote. En nuestro caso queremos habilitar la validación remota sobre la propiedad UserName. Para ello añado el atributo Remote:

[Required]
[Display(Name = "User name")]
[Remote("CheckUserAvailability", "Account", ErrorMessage = "This user name is not allowed.")]
public string UserName { get; set; }

El primer parámetro es la acción que va a validar el campo, la segunda es el controlador. Finalmente ponemos el mensaje de error (igual que las otras validaciones).

3. Creando el código de validación

Finalmente tenemos que crear la acción del controlador:

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public ActionResult CheckUserAvailability(string username)
{
var validUserName = Membership.FindUsersByName(username).Count == 0;
return Json(validUserName, JsonRequestBehavior.AllowGet);
}

Fijaos lo simple que es: Usamos el membership provider para ver si existe algún otro usuario con el mismo nombre, y devolvemos un booleano (codificado en json). El uso de [OutputCache] es para evitar que MVC me cachee los resultados de las peticiones.

Y listos! Con eso ya hemos terminado.

Podemos ejecutar la aplicación, registrar un usuario y luego intentar darnos de alta de nuevo y veremos el error:

image

4. Y que pasa “en la trastienda”?

Si inspeccionamos las peticiones veremos que cada vez que cambia el texto se realiza una petición Ajax. Esta vez en lugar de firebug he usado las Developer Tools de IE9 (pulsar F12 para que os aparezcan):

image

Estas son las peticiones que se realizan si entro “eiximenis” en el campo de nombre de usuario. Si las contáis veréis que faltan peticiones. Eso es simplemente he pulsado dos teclas  muy rápido y las peticiones supongo que no se encolan

Si miramos los detalles de una petición vemos lo siguiente:

image

Fijaos en el primer campo (Request) me indica la URL de la petición. En mi caso es /Account/CheckUserAvailability?UserName=eiximenis

Es decir se pasa el valor por querystring (eso no es problema alguno para MVC que soporta el binding de datos en el querystring desde siempre).

5. Y qué código me genera eso en el navegador?

Recordáis que MVC3 apuesta fuertamente por el unobstrusive javascript? Pues eso es lo que nos genera:

<input data-val="true" 
data-val-remote="This user name is not allowed."
data-val-remote-additionalfields="*.UserName"
data-val-remote-url="/Account/CheckUserAvailability"
data-val-required="The User name field is required."
id="UserName" name="UserName" type="text" value="" />

Precioso no? Nada de código javascript mezclado por ahí que “ensucie” el html: sólo atributos.

Los atributos data-val-remote-* son los que controlan la validación remota. Para que eso funcione, es necesario que los scripts siguientes estén referenciados:

  1. jquery-1.4.4.min.js
  2. jquery.validate.min.js
  3. jquery.validate.unobtrusive.min.js

Yo los tengo siempre colocados en mi página Master principal (Views/Shared/_Layout.cshtml si usas Razor).

6. Controlando algunos aspectos “avanzados”

Vamos a ver como controlar algunos aspectos más de la validación remota. P.ej. te puede interesar que la llamada a la acción de validación (CheckUserAvailability) se realice via POST y no via GET. Para ello simplemente usa la propiedad HttpMethod del atributo Remote:

[Remote("CheckUserAvailability", "Account",
HttpMethod = "POST", ErrorMessage = "This user name is not allowed.")]

Eso añade el atributo data-val-remote-type="POST" al campo HTML generado lo que fuerza que la petición sea usando POST.

Otra cosa interesante es que podemos enviar más de un parámetro a la acción quen realiza la “validación remota”. P.ej. imaginad que a CheckUserAvailability le queremos también pasar el password que ha introducido el usuario (vale, no tiene lógica en ese ejemplo, pero imaginadlo igual :p).

Para ello podemos usar la propiedad AdditionalFields del atributo Remote:

[Remote("CheckUserAvailability", "Account", HttpMethod = "POST",
AdditionalFields = "Password",
ErrorMessage = "This user name is not allowed.")]
public string UserName { get; set; }

Ahora si miramos de nuevo lo que nos manda la petición veremos que junto al campo UserName nos manda el valor del campo Password:

image

Tened presente que el valor de Password puede ser vacío (el usuario puede no haber introducido nada allí todavía). Pero lo importante de esto es que las validaciones remotas no están limitadas a validar UN SOLO campo.

Y con eso terminamos el post de las validaciones remotas en ASP.NET MVC3… Como podeis ver, es un método sumamente potente y sumamente fácil!

Un saludo! 😉

ASP.NET MVC: Binding de datos de sesión a controladores

Muy buenas! Que tal el fin de año? Empachados con turrones, polvorones y demás? En fin, vamos a inaugurar el 2011 y que mejor manera que hacerlo que con un post! 😉

En realidad hubiese querido que este post fuese el último del año anterior, pero no puede publicarlo antes por problemas logísticos. La idea del post surge de un tweet que publicó Luis Ruiz Pavón. Su pregunta era que tal acceder a la sesión desde un Model Binder para poner datos a disposición de los controladores. Mi respuesta fue que yo usaría un value provider, y así llegamos a este post.

Para conseguir binding de los datos de la sesión a los parámetros de un controlador no es necesario crear ningún Model Binder. En MVC2 se introdujo un concepto nuevo (del que ya he hablado varias veces por aquí) que se llama ValueProvider y que es el encargado de acceder donde están los datos y ponerlos a disposición de los Model Binders. Si ignoramos los value providers y hacemos un model binder que acceda a la sesión, entonces realmente nuestro model binder hace dos cosas:

  1. Ir donde están los datos (la sesión) y recogerlos
  2. Enlazar los datos con los parámetros de los controladores

Según la arquitectura de ASP.NET MVC los model binders sólo se encargan de lo segundo, y son los value providers quienes se encargan de lo primero. Así, pues, tened presente la regla:

  1. Si lo que queréis canviar es cómo se enlazan los datos (vengan de donde vengan) a los controladores: cread un model binder
  2. Si lo que queréis es modificar de dónde se obtienen los datos que se enlazan a los controladores: usad un value provider.

En nuestro caso, tal y como se enlazan los valores a los controladores ya nos va bien (el DefaultModelBinder es realmente bueno en su tarea), sólo que queremos que si un dato está en la sesión se coja de allí: necesitamos un value provider nuevo.

Factoría de value providers

En ASP.NET MVC los value providers se crean siempre mediante una factoría y lo que realmente registramos en el runtime son esas factorías. En cada petición ASP.NET MVC le pide a las distintas factorías que creen los value providers necesarios.

Así pues lo primero va a ser crear nuestra factoría, que devolverá objetos de nuestro value provider vinculado a sesión:

class SessionValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
return new SessionValueProvider(controllerContext.HttpContext.Session);
}
}

Simplemente debemos derivar de ValueProviderFactory y en el método GetValueProvider devolver una instancia de nuestro value provider. En mi caso devuelvo una instancia del SessionValueProvider y le paso la sesión en el constructor.

Debemos registrar esa factoría de value providers en el runtime de ASP.NET MVC. Para ello en el Global.asax basta con meter la siguiente línea (usualmente en el Application_Start):

ValueProviderFactories.Factories.Add(new SessionValueProviderFactory());

El value provider

Crear un value provider es “tan sencillo” como implementar la interfaz IValueProvider. De todos modos debemos conocer un poco como funcionan los model binders a los que debemos proporcionar los valores.

Los value providers vienen a ser como un “diccionario enorme” que los model binders consultan cuando quieren obtener un dato. Debemos saber cómo (“con que clave”) nos va a pedir el model binder los datos y como debemos dárselos. En un post mío de hace tiempo ya comenté como funciona el DefaultModelBinder, y allí cuento también la interacción entre el DefaultModelBiner y los value providers.

En fin, que todo ese rollete es para comentaros que muchas veces en lugar de implementar IValueProvider desde cero, es mucho mejor derivar de alguna de las clases que ya hay hechas, y hay una en concreto que nos viene al pelo: DictionaryValueProvider<TValue>. Esta clase implementa un value provider cuya fuente de datos es un diccionario cuyos valores son de tipo TValue. Y que es la sesión en el fondo sinó un gran diccionario cuyos valores son de tipo object?

Así pues creamos nuestra clase que derive de DictionaryValueProvider y lo único que tenemos que hacer es pasarle a nuestra clase base el diccionario que debe usar, que construimos a partir de la sesión:

class SessionValueProvider : DictionaryValueProvider<object>
{
public SessionValueProvider(HttpSessionStateBase session)
: base(CreateDictionary(session), CultureInfo.CurrentCulture)
{

}

private static IDictionary<string, object> CreateDictionary(HttpSessionStateBase session)
{
var entries = session.Keys.Cast<string>().ToDictionary(key => key, key => session[key]);
return entries;
}
}

Trivial no? El método CreateDictionary simplemente crea un IDictionary a partir de los datos de la sesión.

Y listos! Hemos terminado, No necesitamos hacer nada más para que el binding de objetos de sesión funcione. El requisito para que el binding se efectúe es el de siempre: que el nombre del parámetro en la acción del controlador tenga el mismo nombre que la clave de sesión:

public class SessionController : Controller
{
public ActionResult Put()
{
Session["ufo"] = "String en sessión";
Session["complex"] = new Foo()
{
Cadena = "Una cadena en objeto complejo",
Entero = 100,
Lista = new List<int>() {1, 1, 3, 5, 8, 13}
};
return View();
}
public ActionResult Get(string ufo)
{
ViewData["data"] = ufo;
return View();
}

public ActionResult GetClass(Foo complex)
{
return View(complex);
}
}

En este controlador la acción Put coloca dos datos en la sesión: una cadena con clave “ufo” y un objeto de una clase llamada Foo, con clave “complex”. Las dos acciones restantes (Get y GetClass) usan el binding y obtienen los datos de la sesión.

Ventajas de usar el binding para obtener los valores

La ventaja principal de usar el binding para obtener los valores en lugar de acceder a la sesión directamente es que desacopla el código de las acciones de la sesión de HTTP. En definitiva, si quiero probar si la acción Get funciona correctamente, p.ej. usando un unit test, me basta con pasarle una cadena cualquiera. Si en el código de la acción accediese a la sesión debería tener acceso a la sesión (desde la prueba) y rellenarla.

Espero que os sea útil!

Un saludo!

PD: Teneis un proyecto en VS2010 con MVC2 con el código de dicho post en mi skydrive: http://cid-6521c259e9b1bec6.office.live.com/self.aspx/BurbujasNet/ZipsPosts/MvcSessionBinding.zip

[Channel 9] Uso de snippets en VS2010

Muy buenas!

Post cortito, cortito sólo para decir que han publicado en Channel 9 Spain mi vídeo sobre cómo usar los snippets en VS2010.

Si no conoces lo que son, o bien los usas pero no sabes como definirte los tuyos propios, igual el vídeo te puede ayudar! Lo tenéis en:

http://channel9.msdn.com/Blogs/channel9spain/Cmo-usar-Snippets-en-Visual-Studio

Un saludo!

PD: Ayer fue un día intenso en Channel 9, también se publicó el vídeo de Josue Yerai sobre MVVM en Silverlight y el  de Actualidad y futuro sobre HTML5 de Alejandro Martín!

Un saludo!

Opinión: Var o no var… esa es la cuestión.

Hola a todos! Desde hace algunos días estoy usando Resharper. La verdad no era, como decirlo, muy proclive para instalármelo, ya que había tenido no muy buenas experiencas con CodeRush. Seguramente no eran culpa de CodeRush sinó mías, pero bueno… Al final me lo instalé y debo decir que estoy gratamente sorprendido: Es una auténtica maravilla.

Una cosa interesante de Resharper es que te hace sugerencias (que puedes desactivar si quieres, por supuesto) sobre como codificar mejor. Y una de las sugerencias es usar var siempre que se pueda:

image

Fijaos que incluso en un caso trivial como int i=0; nos recomienda que usemos var.

Nota: Primero una pequeña aclaración sobre var: Por si acaso… Recordad que var no es tipado dinámico, ni late-binding ni nada parecido a esto. Var simplemente le indica al compilador que infiera él el tipo de la variable. Pero la variable tiene un tipo concreto y lo tiene en tiempo de compilación. Por lo tanto olvidad todos vuestros prejuicios (si los tenéis) sobre tipos dinámicos.

Hay tres corrientes de opinión al respecto de cuando usar var: Hay gente que opina que debe usarse sólo cuando es necesario (cuando se trabaja con objetos anónimos).

Otros opinan que cuando el tipo ya aparece en la lína de código puede usarse var. Es decir, admiten esto:

var dict = new Dictionary<int, string>();

Porque el tipo de la variable ya aparece en el new. Pero no admiten lo siguiente:

var result = stockManager.GetStocks();

Porque, viendo el código: como se puede saber el tipo de result? (Debes irte a ver que devuelve el método GetStocks).

Por último el tercer grupo de opinión está a favor de usar var siempre. Incluso en los casos más triviales.

Por curiosidad:

  1. La msdn se situa en el primer grupo de opinión (literalmente dice “the use of var does have at least the potential to make your code more difficult to understand for other developers. For that reason, the C# documentation generally uses var only when it is required” – http://msdn.microsoft.com/en-us/library/bb384061.aspx).
  2. Resharper se sitúa en el tercer grupo, como hemos visto
  3. Yo me situaba en el segundo grupo de opinión.

¿Que aporta usar siempre var?

Que Resharper me estuviese continuamente insistiendo en usar var me hizo pensar en el por que de esa razón. Así que lo que hice fue probar y hacerle caso. Y empecé a usar var en todos los sitios. A ver que ocurría.

Y ocurrió una cosa interesante…

Al usar var continuamente pierdes el tipo de la variable de forma visual (es decir no sabes de que tipo es sólo viendo esa línea de código) y entonces te das cuenta de una cosa: que muchos nombres de variables aportan muy poca información sobre que hace realmente la variable. Los detractores de var dicen que puede complicar la lectura de código… pero que es más dificil de entender, esto:

Player plr = GetCurrentPlayer();
Location l = plr.GetCustomLocation();
// Varias líneas de código hablando de "l" y "plr"

o esto:

var player = GetCurrentPlayer();
var location = player.GetCustomLocation();
// Varias líneas de código hablando de "location" y "player"

El tema está en que la variable la declaras en una línea, y la usas en varias más. Evidentemente, si no usas var, la línea que declara la variable te da más información (exactamente el tipo de la variable), información que pierdes si usas var. Pero, como te das cuenta que estás perdiendo esta información, lo que haces es usar lo que resta de la línea para aumentar la claridad. Y que es lo que queda? El nombre de la variable.

Al usar var en todos los sitios te fuerzas a poner nombres más declarativos a tus variables, que expresen lo que la variable hace. Y todos sabemos que esa es una muy buena práctica. Y a veces no la seguimos, y una de las razones es que al tener una línea tipo:

Location l = new Location();

Mentalmente piensas: <<Ya se ve que “l” es una Location. Ya queda claro.>>

Pero no es cierto, porque al cabo de unas cuantas líneas te aparece una “l” y tienes que recordad que era una Location.

Mientras que si usas var, cuando escribes la línea tiendes a usar nombres más descriptivos, porque escribir:

var l = new Location();

Hace como daño a la vista 🙂

Así que la sugerencia de usar var siempre, personalmente no me parece muy desacertada, y creo que voy a tomar esa opción de ahora en adelante.

Pero… Y vosotros? ¿Que opináis al respecto?

Un saludo!

PD:  También creo que hay otra razón para que Resharper nos guie a usar siempre var y es que el código con var es más fácil de refactorizar (menos cambios) que el que usa declaraciones explícitas.

ASP.NET: Obtener el ID del usuario actual

Buenas!

No se vosotros, pero yo cuando desarrollo mis aplicaciones, si uso FKs de la otabla de usuarios, las hago en base al ID del usuario, nunca en base a su nombre. Así pues, saber el ID del usuario actualmente autenticado en mi aplicación es algo fundamental.

Primero, para saber el nombre del usuario autenticado podemos usar:

string userName = HttpContext.Current.User.Identity.Name;

El tema está en que las mentes pensantes que parieron el sistema de proveedores de autenticación en ASP.NET no tuvieron a bien a poner un campo para guardar el ID.

Por suerte obtenerlo es trivial:

int i = (int)Membership.GetUser().ProviderUserKey;

Ojo con ese código: Yo uso un membership provider propio, ya que mi base de datos usa ints para los IDs de usuarios. Si usáis el membership provider que viene por defecto en ASP.NET, el cast lo debéis hacer a Guid y no int.

Bueno todo muy bonito, pero antes que descorchéis el cava: eso hace una llamada a la base de datos. Además se trae todos los campos del registro correspondiente de la tabla de usuarios (que si usáis el membership provider que viene por defecto tiene la hostia y pico). O sea que cuidado con usar eso a mansalva… 🙂

Eeeerrr… ¿se puede SIN necesidad de acceder a la base de datos?

Bueno… esa es la gran pregunta, no nos vamos a engañar 😉 Hay varias maneras de poder acceder al ID del usuario sin hacer un round-trip a la base de datos, pero a si a bote pronto se me ocurren dos:

  1. Guardarlo en una variable de sesión: Podemos guardar el ID en una variable de sesión y consultarla cuando la necesitamos. Para una escalabilidad máxima podéis no usar sticky sessions y en el Session_Start guardar dicha variable con el ID. Si no usáis sticky sessions un mismo usuario puede iniciar sesión en varios IIS a la vez, pero en nuestro caso no es problemático (simplemente se consultará el ID del usuario cada vez que inicie sesión). Eso sí, estoy asumiendo que no guardáis nada más en la sesión (es decir que funcionalmente no dependéis de la sesión).
  2. Guardarlo en la cookie de autenticación del usuario. Esto no es, ni de lejos tan sencillo como el punto anterior, pero ya que hemos llegado hasta aquí…

Modificar la cookie de autenticación

Primero debemos hacer que cuando se cree la cookie de autenticación se añada el ID del usuario. En mi caso, como siempre, uso ASP.NET MVC, así que modificaré el código de AccountController (que es el que genera VS). Para aplicaciones webforms ese código debe colocarse cuando se va a hacer login del usuario.

En el código por defecto que genera VS para autenticar un usuario se usa:

public void SignIn(string userName, bool createPersistentCookie)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");

FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
}

Este código está en la clase FormsAuthenticationService (dentro de AccountsModel.cs) y no tiene ningún secreto: lo que hace es crear la cookie de autenticación de ASP.NET.

En nuestro caso vamos a modificar ese código por el siguiente:

public void SignIn(string userName, bool createPersistentCookie)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
int id = 100; // Aquí va el ID del usuario que pillaríamos de la BBDD
string userData = id.ToString();
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(30), createPersistentCookie, userData);
string encTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
HttpContext.Current.Response.Cookies.Add(faCookie);
}

Lo que hacemos es crear una cookie, con datos adicionales (el ID del usuario).

Ahora lo que nos toca es la otra parte: reemplazar el valor de HttpContext.Current.User.Identity por uno propio que tenga el ID. Para ello usamos el evento PostAuthenticate_Request:

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
CustomIdentity identity = new CustomIdentity(authTicket.Name, authTicket.UserData);
GenericPrincipal newUser = new GenericPrincipal(identity, new string[] {});
Context.User = newUser;
}
}

Recogemos la cookie de autenticación, desencriptamos el ticket de autenticación por forms y con los datos (el nombre y el UserData) creamos un objeto de tipo CustomIdentity, clase nuestra que nos implementa IIdentity. Luego la incrustamos dentro de un GenericPrincipal y lo establecemos a la propiedad User del HttpContext.

Nota: El segundo parámetro del constructor de GenericPrincipal es el array de roles a los que pertenece el usuario. En mi caso no uso roles, así que le asigno un array vacío.

La clase CustomIdentity es tal y como sigue:

class CustomIdentity : IIdentity
{

public CustomIdentity(string name, string id)
{
IsAuthenticated = true;
Name = name;
Id = Int32.Parse(id);
AuthenticationType = "Forms";
}

public string AuthenticationType { get; private set; }
public bool IsAuthenticated { get; private set; }
public string Name { get; private set;}
public int Id { get; private set; }
}

De esta manera, ahora podemos al Id del usuario, desde un controlador:

CustomIdentity ci = (CustomIdentity)ControllerContext.HttpContext.User.Identity;
int IdUsuario = ci.Id;

Un misterio con el que me he encontrado es que el código de PostAuthenticateRequest si se pone en AuthenticateRequest (que parece que debería funcionar igual), se queja diciendo que la clase “CustomIdentity” no es serializable. No tengo muy claro porque ocurre eso y eso si que parece ser propio de MVC. Aquí hay más información al respecto: http://stackoverflow.com/questions/1884030/implementing-a-custom-identity-and-iprincipal-in-mvc

Y Listos!

Con esto podemos acceder al ID de nuestros usuarios sin necesidad de usar para nada la base de datos. Además, dado que estamos usando el sistema de autenticación de ASP.NET (no hacemos nada raro), nos siguen funcionando los filtros de autenticación como [Authorize].

Un saludo!

Referencia: http://stackoverflow.com/questions/1064271/asp-net-mvc-set-custom-iidentity-or-iprincipal

[Evento] Recordatorio: Este jueves… Hasta dónde podemos llegar con ASP.NET MVC?

Hola!

Este es un post para recordaros que mañana jueves 2 de diciembre, sobre las 19:00 (hora española) doy un WebCast de la mano de la gente del Lleida DotNetClub.

Veremos paso a paso (como los New Kids on the Blockstep by step, uououoooo baby’) la realización de Porrazo, el sistema de Porras on-line que ha hecho de Porrazo Enterprise la empresa más cotizada de la bolsa…

imageimage

Sí… es cierto que a la gente de Porrazo Enterprise, les falta un diseñador gráfico, así que si os animáis les podéis mandar un CV 🙂

Un poco los distintos puntos que vamos a ver seran:

  1. Empezando el proyecto (estructura de un proyecto MVC3)
  2. Que no entre todo el mundo! (creción de un Membership Provider propio)
  3. Organizando el código (desacoplando dependencias con Unity)
  4. Consultando datos en la bbdd (El patrón repositorio)
  5. Usando un poco de Ajax (devolviendo Json desde el servidor)
  6. La transformación de Json en Html (aka templates)
  7. Recogiendo los datos enviados des del cliente (aka binding)
  8. Guardando datos en la bbdd: Patrón Unit Of Work
  9. ¿Por qué los datos no se guardan? El ciclo de vida de los objetos
  10. Añadiendo un administrador (creación de un Role Provider propio)
  11. Añadiendo un módulo de administración (áreas MVC)
  12. Componiendo presentación (vistas parciales e inclusión en cliente)
  13. Editando detalles (Sí… podemos poner Grids!)
  14. Ventanas flotantes (Unos popups brutales!)

Espero que os resulte interesante! 🙂

El link para el registro está en: WebCastEventDetails.aspx-EventID=1032471331&EventCategory=4&culture=es-ES&CountryCode=ES

Un saludo! 😉

Trick: Enviar datos en JSON usando POST

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!

[Evento] Hasta donde se puede llegar con ASP.NET MVC?

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!

C# Básico: Covarianza en genéricos

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!!!

Saca tus scripts de tu código HTML

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.