[WebCast] ASP.NET MVC para UOC DotNetClub aplazada al 28 de Junio

El WebCast sobre ASP.NET MVC que debía realizar hoy (21 junio) para el UOC DotNetClub se aplaza una semana hasta el 28 de junio.

La razón principal es que no vamos a hacerle la competencia a La Roja que juega justo a la misma hora, y me consta que Casillas y Villa entre otros desean asistir al WebCast… 😛 😛 😛 Y tampoco vamos a olvidarnos de los hondureños, claro!!!

Así que… nos vemos el 28!!!!

Saludos y perdonad las molestias!

PD: Os paso el enlace para que os podáis registrar: https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032454315&Culture=es-ES

PD2: Si alguien desea que hablemos de algún tema en particular de MVC que me mande un mensaje a mi cuenta de twitter (@eiximenis) o bien que contacte conmigo usando el enlace “contactar” de este mismo blog!

Usa las interfaces… que para eso están!

Ole! Vaya título tan imperativo me ha salido, eh??? Un post cortito para comentar un problemilla que hemos tenido en casa de un cliente, y que al final era debido por no usar interfaces (en nuestro caso interfaces COM).

El problemilla…

En todos los ordenadores de desarrollo el sistema funcionaba perfectamente (como siempre… en mi máquina funciona!).

En los ordenadores de prueba el sistema daba error, concretamente se quejaba que no encontraba el ensamblado mshtml.dll. Nosotros usábamos una referencia contra el ensamblado PIA que está en “%PROGRAMFILES%Microsoft.NETPrimary Interop Assemblies” y que se llama Microsoft.mshtml.dll.

Vimos que efectivamente dicho ensamblado no se distribuía junto con nuestro proyecto y que no estaba en la GAC de los ordenadores, así que cambiamos la referencia para que fuese con Copy Local=true. Ahora sí que aparecia el ensamblado: Microsoft.mshtml.dll.

Desplegando esta versión de Microsoft.mshtml.dll el sistema… seguía sin funcionar. Pero ahora ya no daba errores de carga de assemblies ni de validaciones falladas de strong name, sino que daba una excepción:

Unable to cast COM object of type ‘System.__ComObject’ to class type ‘mshtml.HTMLDocumentClass’. COM components that enter the CLR and do not support IProvideClassInfo or that do not have any interop assembly registered will be wrapped in the __ComObject type. Instances of this type cannot be cast to any other class; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.

El código que daba el error era el siguiente:

var mainDocument = (mshtml.HTMLDocumentClass)webBrowserControl.Document.DomDocument;

La solución

Bueno… Lo primero que pensamos era que alguna diferencia de versión de internet explorer podía causar eso, pero descartamos el tema: aunque es cierto que había distintas versiones (aunque todos los ordenadores tenían la 6(*), no todos tenían las mismas actualizaciones) había un ordenador de desarrollo que tenía la 8… Si compilábamos en dicho ordenador podíamos ejecutar el programa en otros ordenadores de desarrollo que tuvieran la 6. Estaba claro que interet explorer no era el problema.

Entonces? Bueno… si habéis leído el título del post ya sabréis la causa: estábamos utilizando directamente las clases COM (P.ej. HTMLDocumentClass) en lugar de usar la interfaz (p.ej. IHTMLDocument2). Cambiando el código por el siguiente:

var mainDocument = (mshtml.IHTMLDocument2)webBrowserControl.Document.DomDocument;

Todo funcionó a la perfección!

¿Conclusion? Pues eso… usad las interfaces (COM) que para eso están! 🙂

Un saludo!!!!

(*) Sí, sí, sí… Internet Explorer 6 ya no está suportado por MS, es más viejo que matusalén, tienes más agujeros de seguridad que un queso gruyere pero… en muchos sitios sigue formando parte de la plataforma corporativa.

ASP.NET MVC: Create tus propias validaciones

Una de las noverdades de ASP.NET MVC 2 es que lleva integrado el uso de Data Annotations para permitirnos validar los modelos. En ASP.NET MVC 1 también era posible pero no era un proceso tan integrado como con la nueva versión.

Mediante Data Annotations podemos indicar un conjunto de reglas que deben cumplir las propiedades de nuestros modelos. Así para indicar que el campo Login es obligatorio basta con decorar la propiedad correspondiente:

public class UserData
{
[Required(ErrorMessage="El nombre de usuario NO puede estar vacío")]
public string Login { get; set; }
}

Y luego dejar que el sistema de ASP.NET MVC 2 haga “la magia”: cuando el model binder deba reconstruir el objeto UserData a partir de los datos de la request, si no existe el dato para la propiedad Login, automáticamente nos pondrá el ModelState a inválido:

[HttpPost()]
public ActionResult Index(UserData data)
{
if (!ModelState.IsValid) {
// Hay errores en el modelo (data.Login está vacío)
return View(data);
}

// El modelo es correcto... realizar tareas
}

Pero bueno… lo normal es que los atributos que vienen de serie se te queden “cortos” y que tarde o temprano necesites crear tus propias validaciones… y este es el motivo de este post.

Vamos a realizar un ejemplo sencillo: crearemos una validación que indique si una propiedad string contiene una representación válida de un número entero. Vamos a soportar notación decimal, hexadecimal (prefijada por 0x), octal (prefijada por 0) y binaria (prefijada por 0b). Así:

  • 1234567890 es una cadena válida (decimal)
  • 0xaa112d es una cadena válida (hexadecimal prefijada por 0x)
  • 01239 es una cadena inválida (prefijo 0 indica octal y 9 no es carácter octal).
  • 0b00112101 es una cadena inválida (prefijo 0b indica binario y el carácter 2 no es binario).

Vamos a ello?

1. Creación de la validación en el servidor

Para crear una validación en el servidor debemos crear un nuevo atributo que herede de ValidationAttribute y que contenga él código de la validación sobrecargando el método IsValid:

public class DeveloperIntegerAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
bool valid = false;
if (value is string && value != null)
{
string sval = value as string;
if (sval.StartsWith("0x") || sval.StartsWith("0X"))
{
valid = CheckChars(sval.Skip(2), "0123456789abcdefABCDEF");
}
else if (sval.StartsWith("0b") || sval.StartsWith("0B"))
{
valid = CheckChars(sval.Skip(2), "01");
}
else if (sval.StartsWith("0"))
{
valid = CheckChars(sval.Skip(1), "01234567");
}
else
{
valid = CheckChars(sval, "0123456789");
}
}
return valid ? ValidationResult.Success : new ValidationResult(ErrorMessage);
}

private bool CheckChars(IEnumerable<char> str, string validchars)
{
return str.All(x => validchars.Contains(x));
}
}

Como podéis ver el código es realmente sencillo: debemos comprobar que el parámetro “value” satisface nuestras condiciones y en este caso devolver ValidationResult.Success y en caso contrario devolver un ValidationResult con el mensaje de error asociado.

Ahora ya podemos aplicar nuestro nuevo flamante atributo [DeveloperInteger] a nuestras clases de modelo:

public class FooModel
{
[Required]
[DeveloperInteger(ErrorMessage="Numero no correcto (se aceptan prefijos 0 - octal, 0x - hexa, 0b - binario y ninguno para decimal")]
public string DeveloperNumber { get; set; }

[Required]
public string OtraCadena {get; set;}
}

Y listos! Con esto la validación ya está integrada en el sistema de ASP.NET MVC. Podemos comprobarlo si creamos una vista para crear datos de tipo FooModel:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<CustomValidations.Models.FooModel>" %>
<!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 runat="server">
<title>Index</title>
</head>
<body>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.DeveloperNumber) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.DeveloperNumber) %>
<%: Html.ValidationMessageFor(model => model.DeveloperNumber) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.OtraCadena) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.OtraCadena) %>
<%: Html.ValidationMessageFor(model => model.OtraCadena) %>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
</body>
</html>

Este código es el código estándard que genera Visual Studio si añadimos una vista tipada para Crear objetos FooModel. Fijaos en el uso de ValidationMessageFor para mostrar (en caso de que el modelo no esté correcto) los mensajes de error correspondientes.

Y finalmente como siempre en el controlador, el par de métodos para mostrar la vista para entrar datos y para recoger los datos y mirar si el modelo es válido:

public ActionResult Index()
{
return View();
}

[HttpPost()]
public ActionResult Index(FooModel data)
{
if (!ModelState.IsValid)
{
return View(data);
}
else
{
// modelo es correcto
return RedirectToAction("Hola");
}
}

Más fácil imposible, no??? 🙂

2. Validación en Javascript

Crear validaciones en servidor es muy fácil, pero ahora lo que se lleva es validar los datos en el cliente. Esto hace nuestra aplicación más amigable ya que le evitamos esperas al usuario (no enviamos datos incorrectos al servidor).

Nota: Se ha repetido innumerables veces pero no está de más decirlo de nuevo: Las validaciones en cliente no pueden sustituir nunca a las validaciones en servidor. El objetivo de validar en cliente no es garantizar la seguridad ni la consistencia de los datos, és únicamente proporcionar mejor experiencia de usuario. Siempre debe validarse en servidor, siempre!

Para validar en cliente debemos realizar tres pasos: Habilitar la validación de cliente en la vista, activarla en servidor y crear el código javascript. Veamos cada uno de esos pasos.

El primero es el más fácil, basta con añadir la llamada al método EnableClientValidation() que está en el HtmlHelper. Este método es de la Microsoft Ajax Library así que debéis referenciarla con tags <script>:

<head runat="server">
<script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script type="text/javascript" src="../../Scripts/MicrosoftMvcValidation.js"></script>
<title>Index</title>
</head>
<body>
<% Html.EnableClientValidation(); %>

De esta manera veréis p.ej. que automáticamente ya nos valida si los campos de texto están vacíos (porque usábamos [Required]). Obviamente nuestra validación propia, no la realiza en javascript… veamos como podemos hacerlo.

Primero debemos activar la validación en servidor, y eso se consigue creando una clase derivada de DataAnnotationsModelValidator<TAttr> donde TAttr es el tipo del atributo que tiene la validación, en nuestro caso DeveloperIntegerAttribute. En esta clase debemos redefinir el método GetClientValidationRules para devolver la lista de validaciones en cliente a ejecutar (métodos javascript a llamar).

public class DeveloperIntegerValidator : DataAnnotationsModelValidator<DeveloperIntegerAttribute>
{
private string message;
public DeveloperIntegerValidator(ModelMetadata metadata, ControllerContext cc, DeveloperIntegerAttribute attr)
: base(metadata, cc, attr)
{
message = attr.ErrorMessage;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRule()
{
ValidationType = "devinteger",
ErrorMessage = message
};
// Aquí podríamos añadir parámetros a la función javascript:
// rule.ValidationParameters.Add("parametro", valor);
return new[] { rule };
}
}

Fijaos que devolvemos una colección de objetos ModelClientValidationRule que representan los métodos javascript a llamar para realizar nuestra validación (podemos asociar más de uno).

Un paso adicional que debemos realizar es indicar que la clase DevelolperIntegerValidator gestiona las validaciones en cliente para DeveloperIntegerAttribute y para ello añadimos la siguiente línea en global.asax (p.ej. en Application_Start):

DataAnnotationsModelValidatorProvider.RegisterAdapter(
typeof(DeveloperIntegerAttribute), typeof(DeveloperIntegerValidator));

Ahora ya sólo nos queda crear nuestro método javascript. Realmente no tenemos una función llamada devinteger sino que accedemos a Sys.Mvc.ValidatorRegistry.validators y establecemos una entrada llamada devinteger cuyo valor es un método que recoge los parámetros de validación (si hubiese, en nuestro caso no hay) y devuelve otra función que es la que realiza la validación…

Sí, parece complicado pero tampoco lo es tanto:

Sys.Mvc.ValidatorRegistry.validators["devinteger"] = function (rule) {
// Si tuvieramos un parametro llamado parametro lo recogeríamos aqui:
// var parameter = rule.ValidationParameters["parametro"];
// Debemos devolver la función que realiza la validación
return function (value, context) {
var svalue = "" + value;
var chars = "0123456789";
var radix = 10;
var start = 0;
if (svalue.substr(0, 2) == "0x" || svalue.substr(0, 2) == "0X") { chars = "01234567890abcdefABCDEF", start = 2; }
else if (svalue.substr(0, 2) == "0b" || svalue.substr(0, 2) == "0B") { chars = "01"; start = 2; }
else if (svalue.search(0, 1) == "0") { chars = "01234567"; start = 1; }

return (function (str, chars) {
var ok = true;
for (var i = 0; i < str.length; i++) {
var char = str.charAt(i);
ok = chars.indexOf(char) != -1;
if (!ok) break;
}
return ok;
})(svalue.substring(start), chars) ? true : rule.ErrorMessage;
};
};

Fijaos en el return function (value, context). Aquí devolvemos la función anónima que realmente realiza la validación. Dicha función recibe dos parámetros: value, que es el valor a evaluar y context que es un contexto de validación. El código dentro de esta función anónima debe devolver true si el value valida satisfactoriamente y la cadena de error en caso contrario.

Y listos! Ya tenemos la validación por javascript en cliente! Si alguien sabe alguna manera mejor de realizar dicha validación en javascript que me lo diga (sí, javascript no es mi fuerte). Yo intenté usar parseInt, pero dado que parseInt valida los carácteres válidos hasta que encuentra el primer inválido no me servia (para mi 0x1j es inválido y no el número 1).

Y listos! Ya tenemos la validación en cliente para nuestro validador propio… Que os parece? Fácil, no???? 🙂

Un saludo!

Sobre ir recorriendo enumerables…

El otro día, Oren Eini (aka Ayende) escribió en su blog un post, en respuesta a otro post escrito por Phil Haack (aka Haacked). En su post Phil mostraba un método extensor para comprobar si un IEnumerable<T> era null o estaba vacío (y sí, Phil usa Any() en lugar de Count() para comprobar si la enumeración está vacía):

public static bool IsNullOrEmpty<T>(this IEnumerable<T> items) {
return items == null || !items.Any();
}

Aquí tenéis el post de Phil: Checking For Empty Enumerations

Y este es el de Oren: Checking For Empty Enumerations

Oren plantea una cuestión muy interesante al respecto de los enumerables y es la posibilidad de que haya enumeraciones que sólo se puedan recorrer una sóla vez. En este caso el método de Phil fallaría, puesto que al llamar a .Any() para validar si hay un elemento este elemento sería leído (y por lo tanto se perdería) por lo que cuando después recorriesemos el enumerable no obtendríamos el primer elemento.

Pero el tema es… ¿pueden existir enumerables de un sólo recorrido? Pues poder, pueden pero mi opinión personal es que no son enumerables válidos.

Vayamos por partes… Que es un enumerable? Pues algo tan simple como esto:

public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}

Nota: Si no os suena eso de “out” es una novedad de C# 4 que nos permite especificar covarianza en el tipo genérico. No afecta a lo que estamos discutiendo en este post. Tenéis más info en este clarificador post de Matt Hiddinger.

Bueno… resumiendo lo único que podemos hacer con un enumerable es… obtener un enumerador. Y que es un enumerador? Pues eso:

public interface IEnumerator<out T> : IDisposable, IEnumerator
{
T Current { get; }
// Esto se hereda de IEnumerator
object Current { get; }
bool MoveNext();
void Reset();
// Esto se hereda de IDisposable
void Dispose();
}

Un enumerador es lo que se recorre: Tenemos una propiedad (Current) que nos permite obtener el elemento actual así como un método MoveNext() que debe moverse al siguiente elemento (devolviendo true si este movimiento ha sido válido). Hay otro método adicional Reset() que debe posicionar el enumerador antes del primer elemento, aunque en la propia MSDN se indica que no es un método de obligada implementación. Así pues, ciertamente no podemos asumir que un IEnumerator se pueda recorrer más de una vez. Así que no lo hagáis: asumid que los IEnumerator sólo pueden recorrerse una vez.

Pero que un IEnumerator sólo pueda recorrerse una vez no implica que no pueda obtener dos, tres o los que quiera IEnumerator a partir del mismo IEnumerable: puedo llamar a GetEnumerator() tantas veces como quiera.

Y, ahí está el quid de la cuestión del post de Oren: el método Any() crea un IEnumerator y luego el foreach crea otro IEnumerator. Así pues en este código:

void foo(IEnumerable<T> els)
{
if (els.Any()) {
foreach (var el in els) { ... }
}
}

Se crean dos IEnumerator: uno cuando se llama a Any() y otro cuando se usa el foreach. Y ambos IEnumerators nos permiten recorrer el IEnumerable des del principio: por eso no perdemos ningún elemento (al contrario de lo que afirma Oren en su post).

Conclusión

Antes he dicho que pueden existir IEnumerables que solo se puedan recorrer una sola vez, pero que en mi opinión no son correctos. Cuando digo que pueden existir me refiero a que se pueden crear, cuando digo que (en mi opinión) no son correctos me refiero a que según la msdn (http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.getenumerator.aspx) la llamada a GetEnumerator debe:

  • Devolver un enumerador (IEnumerator) que itere sobre la colección (Returns an enumerator that iterates through a collection).
  • Inicialmente el enumerador debe estar posicionado antes del primer elemento (Initially, the enumerator is positioned before the first element in the collection).

Por lo tanto de aquí yo interpreto que cada vez que llame a GetEnumerator obtendré un enumerador posicionado antes del primer elemento, y dado que en ningún momento se me avisa que un IEnumerable pueda admitir una SOLA llamada a GetEnumerator(), entiendo que puedo obtener tantos enumeradores como quiera y que cada llamada me devolverá un IEnumerator posicionado antes del primer elemento.

Así que podéis usar el método de Phil para comprobar si un IEnumerable está vacío sin miedo a perder nunca el primer elemento!

Un saludo!

[WebCast] ASP.NET MVC con UOC DotNetClub

Hola!

Jesús Bosch ha tenido a bien proponerme a que de un WebCast de introducción ASP.NET MVC para el UOC DotNetClub.

Así pues el próximo lunes 21 de Junio a las 20:00 (hora de España) estáis todos invitados.

La página para registrarse está en https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032454315&EventCategory=4&culture=es-ES&CountryCode=ES y allí veréis la agenda, pero básicamente vamos a ver como construir aplicaciones ASP.NET MVC, intentando desterrar algunos falsos mitos como que no es productivo o que estamos volviendo a los 90.

No son necesarios conocimientos previos de ASP.NET MVC así que si has oído a hablar de este nuevo framework y te interesa (y si desarrollas aplicaciones web en tecnología MS debería interesarte)… pásate por el webcast!!! 🙂

Un saludo!

PD: Recuerda que la cuestión no es si aprenderás o no ASP.NET MVC algún dia… la cuestión es cuando lo harás! 🙂

[Editado 21/06]: Se ha retrasado una semana (hasta el 28). Más detalles: http://geeks.ms/blogs/etomas/archive/2010/06/21/webcast-asp-net-mvc-para-uoc-dotnetclub-aplazada-al-28-de-junio.aspx

Novedades de Unity 2.0

Unity, el contenedor IoC de Microsoft, hace algunas semanas que tiene nueva versión: la 2.0. Y viene con algunas novedades interesantes respecto a la versión anterior, que os comento brevemente 🙂

Por fin… un único assembly!

Vale que Unity era poco más que un wrapper sobre ObjectBuilder2 pero tampoco era necesario que nos lo recordaran continuamente… ahora ya no tendremos que añadir la referencia a ObjectBuilder2 además de la referencia a Unity cada vez… Ahora existe un solo assembly: Microsoft.Practices.Unity.dll. ¿Un detalle sin apenas importancia? Pues probablemente 🙂

Resoluciones deferidas

Esta funcionalidad nos permite resolver tipos con Unity sin tener una dependencia contra Unity. P.ej. imagina que tenemos Unity configurado de la siguiente manera:

IUnityContainer uc = new UnityContainer();
uc.RegisterType<IA, A>();

Y tenemos un método que necesita construir un objeto IA a través de Unity… Antes debíamos pasarle el contenedor Unity:

static void OldFoo(IUnityContainer ctr)
{
// ... Código antes de resolver IA ...
IA a = ctr.Resolve<IA>();
}

Ahora, con Unity 2.0 podemos obtener un resolvedor (perdonad por la palabreja) que no es nada más que un delegate que cuando sea invocado llamará a Resolve de Unity. Esto nos permite que la función OldFoo no tenga dependencia alguna contra Unity:

static void NewFoo(Func<IA> resolver)
{
// ... Código antes de resolver IA ...
IA a = resolver();
}

Y la llamada a NewFoo quedaría de la forma:

var resolver = uc.Resolve<Func<IA>>();
NewFoo(resolver);

De esta manera el método NewFoo no necesita para nada el contenedor Unity 🙂

Paso de parámetros en Resolve

Esto permite pasar parámetros a un objeto cuando se llama a su método Resolve.

Supon que tenemos lo siguiente:

interface IB { }

class B : IB
{
public B(int value) { }
}

Y tenemos un mapping declarado en Unity:

IUnityContainer uc = new UnityContainer();
uc.RegisterType<IB, B>();

Como es de esperar la siguiente llamada falla:

IB b = uc.Resolve<IB>();
// Exception is: InvalidOperationException - The type Int32 cannot be constructed.

Unity se queja, porque cuando va al constructor de la clase B se encuentra que le debe pasar un parámetro de tipo Int32 (int). Pero como no tiene ningún mapeo de int, se queja.

Para solucionar este caso podemos usar los ResolverOverride. P.ej. para pasarle el valor 3 al parámetro “value” basta con usar:

IB b = uc.Resolve<IB>(new ParameterOverride("value", 3));

Pero no solo nos sirven para especificar valores de parámetros cuyos tipos no estén registrados en el contenedor, también podemos indicarle valor a un parámetro incluso en el caso que Unity pudiese proveer un valor para el parámetro:

interface IA { }
class A : IA { }
interface IB { IA A { get; } }
class B : IB
{
public IA A { get; private set; }
public B(IA a)
{
A = a;
}
}

class Program
{
static void Main(string[] args)
{
IUnityContainer uc = new UnityContainer();
uc.RegisterType<IA, A>(new ContainerControlledLifetimeManager());
uc.RegisterType<IB, B>();
IA a1 = uc.Resolve<IA>();
IA a2 = uc.Resolve<IA>();
IB b = uc.Resolve<IB>();
IB b2 = uc.Resolve<IB>(new ParameterOverride("a", new A()));
}
}

Dado el siguiente código tenemos que:

  1. a1 == a2 es true puesto que IA está registrado como singleton, por lo que todas las llamadas a Resolve<IA> devuelven el mismo valor
  2. a1 == b.A es true por la misma razón de antes: Cuando Unity debe proporcionar un valor IA al constructor de la clase B, utiliza el método Resolve por lo que devuelve el singleton.
  3. a1 == b2.A es false porque aquí aunque Unity puede proporcionar un valor para el parámetro, el valor especificado en el ParameterOverride tiene preferencia.

Por fin!!! Podemos saber que hay registrado en el contenedor

Se han añadido métodos para saber todos los registros de mapeos del contenedor y para saber si un mapeo en concreto existe:

IUnityContainer uc = new UnityContainer();
uc.RegisterType<IA, A>(new ContainerControlledLifetimeManager());
uc.RegisterType<IB, B>();
bool isTrue = uc.IsRegistered<IA>();
bool isFalse = uc.IsRegistered<IC>();
int numRegs = uc.Registrations.Count();

Por cierto, que dado el siguiente código… cuanto vale numRegs?

Sí habeis dicho 2, habéis fallado… recordad que Unity se registra a si mismo, por lo que realmente numRegs vale 3 (el propio registro de Unity, el de IA y el de IB).

InjectionFactory

InjectionFactory es un mecanismo que permite indicarle a Unity un método (una Func<IUnityContainer, object>, usualmente una lambda expresion) a usar cada vez que deba resolver un objeto especificado. Permite que Unity use factorías nuestras.

Imagina que tenemos una factoría para crear objetos IA:

interface IFactory
{
IA GetNewInstance();
}
class Factory : IFactory
{
public IA GetNewInstance()
{
// Hace lo que tenga que hacer nuestra factoria...
return new A();
}
}

Y ahora deseamos usar Unity para la creación de objetos IA. Pues podemos realizar el siguiente Register:

IUnityContainer uc = new UnityContainer();
uc.RegisterType<IFactory, Factory>(new ContainerControlledLifetimeManager());
uc.RegisterType<IA>(new InjectionFactory
(x => x.Resolve<IFactory>().GetNewInstance()));

En la última línea le estamos indicando a Unity que cada vez que alguien haga un Resolve<IA> ejecute el delegate que le indicamos (en este caso que obtenga una IFactory y llame al método GetNewInstance).

Esto si lo combinamos con lo de las resoluciones diferidas es realmente interesante.

Y estas serían las novedades, a mi juicio, más interesantes de Unity 2 (que no son todas… si las queréis saber todas, las tenéis aquí!).

ASP.NET MVC: Custom Model Binders vs ValueProviders y un ejemplo con JSON…

Hola a todos!

Este post es el cuarto sobre la serie que podríamos llamar “el interior de ASP.NET MCV” y viene a ser un resumen de los tres anteriores. Los anteriores posts fueron:

En este vamos a ver como podemos implementar una característica que no viene de serie en ASP.NET MVC y que es casi imprescindible si estáis implementando una API REST usando MVC: que los controladores MVC sean capaces de procesar peticiones POST que vengan con datos JSON.

El código de la vista que vamos a usar para probar que todo funciona es una vista con un solo botón con id=”btnSend” y el siguiente código javascript:

<script type="text/javascript">
$(document).ready(function () {
$("#btnSend").click(function () {
var data = {
Name: 'edu',
Urls: ['http://twitter.com/eiximenis', 'http://geeks.ms/blogs/etomas']
};
$.ajax({
type: "POST", data: $.toJSON(data), contentType: "application/json; charset=utf-8",
dataType: "json", url: "/Home/Index"
});
});
});
</script>

Cuando se pulse en el botón se serializará el objeto “data” y se enviará via POST a la url /Home/Index. Evidentemente el controlador Home tiene una acción Index que espera datos via POST:

[HttpPost]
public ActionResult Index(UserData data)
{
return View();
}

Y UserData es la clase del modelo que deberá contener los datos de la petición:

public class UserData
{
public string Name { get; set; }
public IEnumerable<string> Urls { get; set; }
public int Id { get; set; }
}

Estamos listos para empezar… 🙂

Usando un ModelBinder propio…

La verdad es que usar un ModelBinder es casi, casi trivial: basta con derivar de DefaultModelBinder y comprobar si la Request tiene el content-type de application/json, y si es el caso usar JavascriptSerializer para deserializar la cadena json:

public class JsonModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (!IsJSONRequest(controllerContext))
{
return base.BindModel(controllerContext, bindingContext);
}
var request = controllerContext.HttpContext.Request;
var jsonStringData = new StreamReader(request.InputStream).ReadToEnd();
return new JavaScriptSerializer()
.Deserialize(jsonStringData, bindingContext.ModelMetadata.ModelType);
}
private static bool IsJSONRequest(ControllerContext controllerContext)
{
var contentType = controllerContext.HttpContext.Request.ContentType;
return contentType.Contains("application/json");
}
}

Recordad de registrar este model binder como el model binder por defecto, colocando lo siguiente en el Application_Start:

ModelBinders.Binders.DefaultBinder = new JsonModelBinder();

Y listos… funciona! O más bien dicho…. parece que funciona

P.ej… ¡hemos perdido las validaciones! P.ej. si añadís la siguiente validación en UserData:

[Range(1,10)]
public int Id { get; set; }

Y ejecutáis de nuevo vereis que el Id es 0 y el modelo sigue siendo válido (ModelState.IsValid vale true). ¿Y eso porque? Pues recordad que es el Model Binder quien las aplica, y nuestro Model Binder simplemente está obviando todas las validaciones.

Pero no sólo esto… si modificamos la vista para que en lugar de enviar el post a /Home/Index lo envíe a /Home/Index?Id=2 cuando recibamos el objeto UserData, su propiedad Id seguirá valiendo 0. Es decir hemos perdido la capacidad de ASP.NET MVC de crear modelos combinando elementos de la request que estén en POST y en querystring.

La razón de todo esto es simple: Un Model Binder no es la mejor manera para realizar esta tarea. Os acordáis cuando hablamos de los Value Providers? Comentamos que su responsabilidad era recoger los datos de la request para después pasárselos a los model binders que los usarán para crear los modelos.

Aquí precisamente tenemos un caso clarísimo de uso de un Value Provider: Debemos inspeccionar los datos de la request y decodificarlos, pero no tenemos ninguna necesidad de redefinir las reglas de creación del modelo.

Usando un Value Provider

Si recordáis el post sobre los value providers, no damos de alta value providers directamente en el sistema sinó factorías de value providers. El siguiente código da de alta una factoría de value providers que leen datos JSON:

public class JsonValueProviderFactory : ValueProviderFactory
{

public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
object jsonData = GetDeserializedJson(controllerContext);
if (jsonData == null)
{
return null;
}

Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

// El DefaultModelBinder es capaz de "bindear" colecciones si los elementos se llaman x[0], x[1], x[2], así
// que si dentro del objeto json tenemos alguna propiedad que sea array vamos a crear una entrada por
// cada elemento del array

AddToBackingStore(backingStore, String.Empty, jsonData);
return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);
}
private static void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)
{
{ // dictionary?
IDictionary<string, object> d = value as IDictionary<string, object>;
if (d != null)
{
foreach (var entry in d)
{
AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
}
return;
}
}

{ // list?
IList l = value as IList;
if (l != null)
{
for (int i = 0; i < l.Count; i++)
{
AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
}
return;
}
}

// primitive
backingStore[prefix] = value;
}

/// <summary>
/// Deserializa el código json que se encuentra dentro del body de la request
/// </summary>
private static object GetDeserializedJson(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// not JSON request
return null;
}

StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
string bodyText = reader.ReadToEnd();
if (String.IsNullOrEmpty(bodyText))
{
// no JSON data
return null;
}

JavaScriptSerializer serializer = new JavaScriptSerializer();
object jsonData = serializer.DeserializeObject(bodyText);
return jsonData;
}


private static string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
}

private static string MakePropertyKey(string prefix, string propertyName)
{
return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;
}

}

Ya… el código es más largo y más complejo que en el caso anterior, pero básicamente hace lo siguiente:

  1. Deserializa el contenido JSON de la request y obtiene un objeto .NET
  2. Insepcciona via reflection dicho objeto y va creando entradas (clave, valor) para cada propiedad. Además trata arrays (colecciones) y subobjetos. P.ej. Si el objeto deserializado tiene una colección de dos elementos llamada Foo, creará dos entradas con claves Foo[0] y Foo[1]. Igualmente si el objeto tiene un subobjeto llamado Bar que tiene dos propiedades, pongamos Baz1 y Baz2 creará dos entradas llamadas Bar.Baz1 y Bar.Baz2.

P.ej. en el el caso que nos ocupa, creará las siguientes entradas:

  • Name
  • Urls[0]
  • Urls[1]

No crea entrada para la propiedad Id, porque dicha propiedad no la estamos enviando via POST en el JSON.

Como vimos en el post sobre el DefaultModelBinder, éste entiende estos nombres de las entradas y con ellas es capaz de crear el modelo y aplicar las validaciones.

Así ahora podemos observar que:

  1. Si la vista manda los datos a Home/Index, el modelo no se valida correctamente, ya que Id vale 0.
  2. Si la vista manda los datos a Home/Index?Id=2 el modelo se valida correctamente, ya que Id vale 2 (el DefaultModelBinder ha combinado los datos de todos los value providers).

Espero que este post os sirva para terminar de comprender cuando usar un Model Binder propio y cuando usar un Value Provider… Recordad: Si queréis modificar de donde (y cómo) de la request se sacan los datos, debéis usar un Value Provider. Si lo que queréis modificar es cómo se interpretan esos datos debéis usar un Model Binder.

Referencias:

Un saludo!!!

VS bloquea assemblies cargados desde la web

¡Hola!

Situación explicada rápidament: Si te descargas un assembly directamente desde internet, y añades una referencia a dicho assembly, la referencia te aparecerá como añadida, pero VS no hará caso de ella. Cuando compiles te aparecerá un error parecido a:

Unable to load the metadata for assembly ‘AvalonDock’. This assembly may have been downloaded from the web.  See http://go.microsoft.com/fwlink/?LinkId=179545.  The following error was encountered during load: Could not load file or assembly ‘AvalonDock, Version=1.2.2691.0, Culture=neutral, PublicKeyToken=85a1e0ada7ec13e4’ or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)

En mi caso, efectivamente me descargué la última versión de AvalonDock (desde su página de descargas puedes descargarte un msi que lo instala o simplemente el assembly que contiene la librería y que es lo que yo hice).

Por suerte el propio mensaje de error de VS es más que expícito y si te vas a la página que menciona (http://go.microsoft.com/fwlink/?LinkId=179545) verás la explicación de lo que hay que hacer: Básicamente cerrar VS y con el explorador de archivos abrir las propiedades del archivo y darle a desbloquear:

image

Y listos! Ya puedes usar tu assembly… ten presente que esto da permisos full trust al assembly, así que… andate con cuidado! 😉

¿Y como sabe VS que el archivo ha sido descargado?

Esta pregunta se aplica no sólo a VS sinó a Windows en general. Como sabe Windows que dicho archivo ha sido descargado de la web? Si lo mueves de carpeta, lo renombras o incluso lo copias a otro ordenador windows seguirá sabiendo que el archivo ha sido descargado de la web.

La respuesta es realmente simple: Windows guarda esta información en el propio archivo y lo hace gracias a una capacidad no muy conocida de NTFS llamada alternate data streams (ADS). Dicha capacidad (insisto de NTFS) permite asociar metadatos a un archivo. Cuando descargamos un archivo de la red, windows crea un ADS en dicho archivo y lo marca como descargado de la red. Los ADS se crean junto con el archivo (no se guardan en ningún sitio separado).

Para poder abrir un ADS basta con saber el nombre de este y añadirlo junto con dos puntos (:) al nombre del archivo. P.ej. el ADS que windows asocia a los archivos descargados de internet se llama “Zone.Identifier”. Así, en mi caso si yo hago:

notepad AvalonDock.dll:Zone.Identifier

obtengo lo siguiente:

image

Cuando pulso el botón de “Unblock” desde el explorador de archivos lo que hace es borrar dicho ADS del archivo.

Usando explorer no podeis saber fácilmente si un archivo contiene ADS o no: aunque los ADS modifican el tamaño real del archivo (puesto que se guardan junto a este), el explorador de archivos sólo os muestra el tamaño del flujo principal (o sea el del archivo sin los ADS) y lo mismo hace el comando “dir” de MS-DOS. Si quereis saber los ADS que tienen vuestros archivos, hay por ahí afuera varios visores de ADS (aunque yo no he probado ninguno).

Por cierto, que os he dicho que los ADS, dado que se guardan junto con el archivo, se mantienen cuando se copia, se modifica o se mueve el archivo y esto es cierto siempre que se use NTFS. Si se copia un archivo que contiene ADS a un sistema que no los soporta (p.ej. FAT32 usado en las llaves USB), el ADS se pierde.

Un saludote!! 😉

Desacopla tus datos XML del formato…

Leyendo este post de Gisela sobre la serialización XML me he decidido escribir este… es lo que tiene la realimentación en los blogs 🙂

El uso de atributos que menciona Gis en su post es realmente genial. A mi me encanta: me permite definir mis clases en un momento y es muy útil cuando leemos datos xml de una fuente externa. Pero hay un detalle que puede ser un problema: El esquema XML está totalmente acoplado de la clase que tiene los datos. Si estamos leyendo de dos fuentes externas que tienen esquemas XML distintos pero tienen los mismos datos, debemos duplicar las clases que serializan esos datos, ya que los atributos a usar serán distintos.

P.ej. supon que tenemos dos fuentes externas, que nos devuelven los mismos datos, pero de forma diferente:

<info>
<usuarios>
<usuario>
<nombre>eiximenis</nombre>
<nombrereal>Edu</nombrereal>
</usuario>
</usuarios>
</info>

<information>
<twitter.users>
<twitter.user name="eiximenis" realname="Edu" />
</twitter.users>
</information>

La información es exactamente la misma, pero el esquema es distinto. Si queremos usar atributos para leer estos dos archivos xml debemos implementar dos conjuntos de clases:

// Clases para leer el 1er formato
[XmlRoot("info")]
public class Info
{
private readonly List<UserInfo> _users;

public Info()
{
_users = new List<UserInfo>();
}

[XmlArray("usuarios")]
[XmlArrayItem("usuario", typeof(UserInfo))]
public List<UserInfo> Usuarios { get { return _users; } }
}

public class UserInfo
{
[XmlElement("nombre")]
public string Nombre { get; set; }

[XmlElement("nombrereal")]
public string NombreReal { get; set; }
}

// Clases para leer el segundo formato
[XmlRoot("information")]
public class TweeterInfo
{
private readonly List<TweeterUserInfo> _users;

public TweeterInfo()
{
_users = new List<TweeterUserInfo>();
}

[XmlArray("twitter.users")]
[XmlArrayItem("twitter.user", typeof(TweeterUserInfo))]
public List<TweeterUserInfo> Users { get { return _users; } }
}

public class TweeterUserInfo
{
[XmlAttribute("name")]
public string Name { get; set; }

[XmlAttribute("realname")]
public string RealName { get; set; }
}

El problema no es que tengamos que realizar el doble de trabajo… es que tenemos dos conjuntos de clases totalmente distintos que no tienen ninguna relación entre ellos. Si desarrollamos un método que trabaje con objetos de la clase Info, dicho método no trabajará con objetos de la clase TweeterInfo aún cuando ambas clases representan la misma información.

La solución pasa, obviamente, por usar interfaces: Ambas clases deberían implementar una misma inferfaz que nos permitiese acceder a los datos:

// Interfaces

public interface ITwitterInfo
{
IEnumerable<ITwitterUser> Users { get; }
}
public interface ITwitterUser
{
string Name { get; }
string RealName { get; }
}

Las interfaces se limitan a definir los datos que vamos a consultar desde nuestra aplicación. En este caso sólo hay getters porque se supone que dichos datos son de lectura sólamente.

El siguiente paso es implementar dichas interfaces en nuestras clases. Lo mejor es usar una implementación explícita. La razón es evitar tipos de retorno distintos entre propiedades que pueden tener el mismo nombre (p.ej. la propiedad Users de TweeterInfo devuelve una List<TweeterUserInfo> mientras que la propiedad de la interfaz ITwitterInfo devuelve un IEnumerable<ITwitterUser> y eso no compilaría:

[XmlRoot("information")]
public class TweeterInfo : ITwitterInfo
{
private readonly List<TweeterUserInfo> _users;

public TweeterInfo()
{
_users = new List<TweeterUserInfo>();
}

[XmlArray("twitter.users")]
[XmlArrayItem("twitter.user", typeof(TweeterUserInfo))]
public List<TweeterUserInfo> Users { get { return _users; } }
}

// error CS0738: 'XmlDesacoplado.Formato2.TweeterInfo' does not implement interface member
// 'XmlDesacoplado.Interfaz.ITwitterInfo.Users'. 'XmlDesacoplado.Formato2.TweeterInfo.Users' cannot
// implement 'XmlDesacoplado.Interfaz.ITwitterInfo.Users' because it does not have the matching return type
// of 'System.Collections.Generic.IEnumerable<XmlDesacoplado.Interfaz.ITwitterUser>'

Como os digo, para que funcione basta con una implementación explícita de la interfaz. Es decir basta con añadir:

// Implementación explícita
IEnumerable<ITwitterUser> ITwitterInfo.Users { get { return Users; } }

En el resto de clases debemos hacer lo mismo (implementar las interfaces).

Ahora todo nuestro código puede trabajar simplemente con objetos ITwitterInfo.

Vale… esto está muy bien, pero como puedo cambiar dinámicamente el “formato” del archivo a leer?

Una posible solución es realizar una clase “lectora” de XMLs, algo tal que así:

class LectorXmls
{
public ITwitterInfo LeerFormato<TSer>(string file) where TSer : class, ITwitterInfo
{
TSer data = default(TSer);
using (FileStream fs = new FileStream(file, FileMode.Open))
{
XmlSerializer ser = new XmlSerializer(typeof(TSer));
data = ser.Deserialize(fs) as TSer;
}
return data;
}
}

Y luego en vuestro código podéis escoger que clase serializadora usar:

ITwitterInfo f1 = new LectorXmls().LeerFormato<Info>("Formato1.xml");

Por supuesto, si quieres que el tipo de la clase serializadora esté en un archivo .config y así soportar “futuros formatos” de serialización no podrás usar un método genérico, pero en este caso te basta con pasar un Type como parámetro:

public ITwitterInfo LeerFormato(string file, Type serType)
{
ITwitterInfo data = null;
using (FileStream fs = new FileStream(file, FileMode.Open))
{
XmlSerializer ser = new XmlSerializer(serType);
data = ser.Deserialize(fs) as ITwitterInfo;
}
return data;
}

Y el valor del Type lo puedes obtener a partir de un fichero de .config.

Un saludo!!!

Redefiniendo GetHashCode

Hola a todos! Un post para comentar paranoias varias sobre algo que parece tan simple como redefinir GetHashCode()…

Primero las dos normas básicas que supongo que la mayoría ya conoceréis:

  1. Si se redefine el método Equals() de una clase debería redefinirse también el método GetHashCode(), para que pueda cumplirse la segunda norma que es…
  2. Si la llamada a Equals para dos objetos devuelve true, entonces GetHashCode() debe devolver el mismo valor para ambos objetos.

Una forma fácil y rápida de implementar GetHashCode() y que cumpla ambas normas es algo así:

public class Foo
{
public int Bar { get; set;}
public int Baz { get; set;}

public override bool Equals(object obj)
{
return obj is Foo && ((Foo)obj).Bar == Bar && ((Foo)obj).Baz == Baz;
}

public override int GetHashCode()
{
return string.Format("{0},{1}", Bar, Baz).GetHashCode();
}
}

Simplemente creamos una representación en cadena del objeto y llamamos a GetHashCode de dicha cadena. ¿Algún problema? Bueno… pues la tercera norma de GetHashCode que no siempre es conocida:

Si a alguien le parece que esta tercera norma entra en contradicción con la segunda, en el caso de objetos mutables… bienvenido al club! 😉

Si no cumplimos esta tercera norma… no podemos objetos de nuestra clase como claves de un diccionario: P.ej. el siguiente test unitario realizado sobre la clase Foo, falla:

[TestClass]
public class FooTests
{
[TestMethod()]
public void FooUsedAsKey()
{
var dict = new Dictionary<Foo, int>();
Foo foo1 = new Foo() { Bar = 10, Baz = 20 };
Foo foo2 = new Foo() { Bar = 10, Baz = 30 };
dict.Add(foo1, 1);
dict.Add(foo2, 2);
foo2.Baz = 20;
int value = dict[foo2];
Assert.AreEqual(2, value); // Assert.AreEqual failed. Expected:<2>. Actual:<1>.
}
}

Esperaríamos que la llamada a dict[foo2] nos devolviese 2, ya que este es el valor asociado con foo2… pero como foo2 ha mutado y ahora devuelve el mismo hashcode que foo1, esa es la entrada que nos devuelve el diccionario… y por eso el Assert falla.

Nota: Si alguien piensa que usando structs en lugar de clases se soluciona el problema… falso: Usando structs ocurre exactamente lo mismo.

Ahora… varias dudas filosóficas:

  1. Alguien entiende que el test unitario está mal? Es decir que el assert debería ser AreEqual(1, value) puesto que si foo2 es igual a foo1, debemos encontrar el valor asociado con foo1, aunque usemos otra referencia (en este caso foo2).
  2. Planteando lo mismo de otro modo: Debemos entender que el diccionario indexa por valor (basándose en equals) o por referencia (basándose en ==)? El caso es entendamos lo que entendamos, la clase Dictionary usa Equals y no ==.
  3. El meollo de todo el asunto ¿Tiene sentido usar objetos mutables como claves en un diccionario?

Yo entiendo que no tiene sentido usar objetos mutables como claves, ya que entonces nos encontramos con todas esas paranoias… y no se vosotros pero yo soy incapaz de escribir un método GetHashCode() para la clase Foo que he expuesto y que se cumpla la tercera condición.

Si aceptamos que usar objetos mutables como claves de un diccionario no tiene sentido, ahora me viene otra pregunta: Dado que es muy normal querer redefinir Equals para objetos mutables, porque se supone que siempre debemos redefinir también GetHashCode? No hubiese sido mucho mejor definir una interfaz IHashable y que el diccionario sólo aceptase claves que implementasen IHashable?

No se… intuyo que la respuesta puede tener que ver con el hecho de que genéricos no aparecieron hasta la versión 2 del lenguaje (en lo que a mi me parece uno de los errores más grandes que Microsoft ha cometido al respecto de .NET), pero quien sabe…

… las mentes de Redmond son inescrutables.

Un saludo!