resXgen (versión beta)

Hola…

Al fin después de algún tiempo renovando todo el código de este proyecto, logro que esté online.

La idea surgió en un evento de SNUG sobre internacionalización de aplicaciones en el que se mostró una aplicación que permitía leer archivos de recursos (resx). La aplicación usaba Bing para realizar la traducción a un idioma seleccionado y visualizaba el resultado. (Estaba hecha en Windows Form).

Al verla, nos gustó la idea pero llevando su funcionalidad a la WEB. Ya en la WEB, pensamos si no sería mucho más interesante obtener la traducción de Bing y de Google y así poder seleccionar de las dos, la más acertada. Aun así, algunas traducciones de Google o Bing podrían no ser correctas, así que decidimos permitir editar la columna de resultados para incluir nuestra propia traducción. Para finalizar, nada más lógico que permitir descargar el archivo de recurso ya traducido al idioma seleccionado…

Así surgió resXgen http://resxgen.odelvalle.com/

Hay un botón de demo que  carga un archivo de recurso que tenemos en la aplicación, de todas maneras, cualquiera puede subir un archivo de recurso, seleccionar el idioma en que se encuentra y probar.

Aún está en Beta y, entre las cosas más importantes que quedan por hacer, es escribir una ayuda o guía para su utilización.

Para reportar cualquier problema o sugerencia he montado un Mantis http://mantis.odelvalle.com/ donde podremos darle seguimiento.

Tratadla suave que aún está  de estreno…

 

EF 4.1 Code First ¿Dónde está la base de datos?

Hola

Me voy a saltar el post pendiente que tengo sobre crear o comentar algún código existente sobre el algoritmo Hi/Lo para los Object ID en Entity Framework. El culpable de este salto es un inquieto colega de proyecto que se puso a probar un artículo que publicamos hace unos días por Twitter sobre MVC 3 con Repositorios e inyección de dependencias usando Entoty Framework.

El artículo no permite descargar el código del ejemplo, así que, gracias Oscar por ahorrarme el trabajo   

Después del prólogo y los agradecimientos, entramos en materia.

El problema, si le podemos llamar así, ya lo tenía anotado como uno de los temas a tratar en esta nueva aventura con Entity Framework. El código causante de todo el debate es este:

La parte que nos importa en la clase Db, la cual hereda del contexto, es la implementación del constructor que llama a la base pasando como parámetro la cadena “DemoDb2”. El parámetro que se le pasa al contexto, según el MSDN, identifica la cadena de conexión o el nombre de la base de datos asociada al modelo que vamos a usar. Este simple código, si no conoces qué hace Entity Framework con él, nos puede costar un “poquito de dolor de cabeza”.

Supongamos que vamos a nuestro archivo de configuración y definimos la siguiente cadena de conexión (Observe que he puesto “DemoDb” y no “DemoDb2)

 

…o simplemente olvidamos que debemos configurar el web.config  para indicar la cadena de conexión. Ejecutamos y “walaaa”    Nuestra aplicación funciona

Si voy a mi servidor en busca de la base de datos me encuentro con que no existe. Pues bien, si EF no encuentra la cadena de conexión o la misma es incorrecta, utiliza el SQL Express que tengamos instalado en local y con autenticación integrada de Windows, crea la base de datos.

Les juro que no estoy haciendo trampas, ninguna de las bases de datos que están tachadas es la del ejemplo 

En mi opinión, hubiera preferido que ocurriera un error y así darme cuenta que tenía algo mal, digamos que algo así…

 Editado: En los comentarios, Pablo Núñez  nos dice cómo lograr que EF pueda tener el mismo comportamiento que NH. (Gracias Pablo)

 

Object ID en EF 4.1

Hola

Hace poco me he comprado el excelente libro de Entity Framework 4.1. He leído mucho sobre este ORM desde sus primeras versiones, pero nunca me resultó lo suficientemente atractivo para usar en un proyecto real sobre el cual me permitieran elegir. Como alternativa a EF tenía NHibernate, ORM que también he usado desde hace mucho tiempo y sobre el cual no tengo dudas en cuanto a funcionalidad o limitaciones que me pueda encontrar.

Entendiendo que no siempre se puede elegir, y por los muchos comentarios que ha generado la nueva versión de EF 4.1 (y más por la posibilidad real de no tener atadas las entidades al ORM) decidí de una vez enfrentarme a él de manera seria, pero es inevitable hacer comparaciones (aunque no sean buenas) 

Aclaro que mi intención jamás sería, ni por asomo, criticar a este excelente ORM, más bien esta serie de artículos va por el camino de conocer bien hasta dónde llegan mis limitaciones en su utilización.

Los Object ID.

Desde cualquier aplicación orientada al dominio se enfoca mucho la necesidad, que yo llamaría obligación, de empezar siempre por el modelo. Es imposible no acordarme de la forma en que casi se suplica en el libro de EF 4.1 (Pág. 78) cuando dice: – “Primero el modelo por favor”.  🙂

Siguiendo tan buen consejo me voy a Visual Studio dispuesto a seguir el ejemplo descrito en el libro empezando por la entidad  “Autor”.

Me detengo en esta ventana en la que remarco la propiedad “Key Property”. ¿Qué significa esto desde el punto de vista del modelo? Pues si estoy pensando en el modelo esta propiedad representa entonces el Object ID de la entidad.

La definición de Object ID está explicada en Mapping Objects To Relational Databases de Scott W. Amble.

We need to assign unique identifiers to our objects so that we can identify them. In relational terminology a unique identifier is called a key, in object terminology it is called an object identifier (OID) although perhaps persistent object identifier would be a better term. OIDs are typically implemented as full-fledged objects in your OO applications and as large integers, or several large integers for larger applications, in your relational schema

Yo creo que la definición ni siquiera necesita traducción 🙂

Algunas funcionalidades de los OID coinciden con su “homólogo” en el modelo relacional. Por ejemplo, mantener y simplificar la relación entre entidades (joins entre tablas en el modelo relacional). Uno de los errores más comunes cuando definimos el modelo es cuando asignamos una responsabilidad al OID dentro del dominio. Los OID NO pueden tener ningún significado lógico “Nada, Zip, Zilch, Zero”  😛 Como dice Scott, toda propiedad que interviene en un modelo con un significado dentro del dominio puede ser potencialmente cambiada. Un OID, no.

Regresando a EF 4.1 (que me pierdo) creo mi entidad y me decido a seleccionar mi estrategia para el OID dentro del modelo.

 

Pues vaya sorpresa :»( solo tengo 3 opciones como estrategia para generar mi OID. ¿Cuál de estas tres opciones puedo elegir?

MSDN dice:

Computed – Un valor generado para INSERT y para UPDATE. o_0  No me he puesto a pensar en qué casos me puede ser útil esta estrategia, ahora mismo no me imagino ninguna porque si el OID cambia durante su ciclo de vida, rompe con su condición de ser único e invariable.

Identity – Un valor que es generado durante el INSERT y que permanece invariable durante las actualizaciones siguientes. Esto es un Identity de SQL en toda regla. ¿Por qué el identity de SQL no es para mí una estrategia válida? Pues Scott lo deja claro cuando dice “An OID should be unique within a class hierarchy, and ideally unique among all objects”

El identity puede generar un mismo valor dentro del modelo para dos entidades distintas y esto rompería también con la definición “ideal” del OID, además, no me vale en absoluto en un sistema distribuido (en un clusters por ejemplo).

None – Generarlo yo implica que tenga que pelearme con el bloqueo de filas para evitar que dos clientes de mi sistema no generen al mismo tiempo un mismo OID. Resultaría tan complejo como se pueda imaginar. Aunque sería la única alternativa y por suerte, hay algoritmos que nos permiten no entrar en polémicas con los bloqueos

NHibernate por su parte propone para los OID las siguientes estrategias : Increment, identity, sequence, hilo(Mi Favorito), seqhilo, uuid.hex, uuid.string, guid, guid.comb, native, assigned y foreign. Las puedes encontrar todas explicadas aquí

Hay que tener en cuenta que NHibernate y EF, trabajan de manera distinta respecto a los OID. NH asegura que se pueda trabajar con el OID de una entidad antes de hacer permanentes los cambios en base de datos, algo muy importante cuando usamos Session per request. Por su parte, EF asegura la unidad dentro del contexto, por lo que no dará el OID hasta que no se guarden los cambios (Si no lo generamos nosotros).

Mi próximo paso en esta serie será ver si puedo crear una estrategia Hi/Lo para usar en EF. La idea del algoritmo Hi/Lo es tener dos valores para formar un único valor. A cada cliente se le asigna un valor Hi y, con un rango de valores Low formaría un identificador único para todo el modelo. Esto garantiza que varios clientes siempre utlizarán valores distintos para los nuevos OID creados y evitaríamos los temas de bloqueos.

¿cómo resuelven esta «limitación» cada uno de los que actualmente usan EF?  😉

Patrón Iterator

Hola de nuevo, hoy ando de nostálgico revisando «viejos» documentos 🙂

Este es uno de los que más me gusta… Patrón iterator, creado al igual que el anterior para el mismo curso de patrones. Les dejo el documento adjunto.

Salu2

Patrón Command

Hola,

Hoy en día, en muchas de las arquitecturas de moda escuchamos hablar de un patrón muy utilizado llamado «Command».  ¿Sabemos con claridad lo que es el patrón Command?

Para quien aún no lo tenga tan claro les dejo un documento creado para un curso de patrones en el MUG de Argentina en el año 2004. Espero les ayude a entender un poquito más a este excelente y tan utilizado patrón.

Salu2

Las consecuencias de trabajar mal…

En estos días parece haber un BOM de análisis sobre pruebas unitarias, sobre metodologías, sobre si hago bien o no en hacer las cosas como se deben hacer, el tiempo que ahorro o el tiempo que pierdo, etc. etc. etc. La historia que me dispongo a contarles es real, así que como ya es costumbre en estos casos no se puede hacer mención de nombres de empresas o detalles del proyecto. Bueno, me chivo un poco: X no es española… 🙂

Llegamos al cliente con un objetivo. Se estaba preparando una demo por una empresa X sobre un conjunto de servicios novedosos que podrían ser implementados o llevados a la realidad en un futuro cercano. Aquello era una DEMO guiada, por lo que solo una persona que conocía todo el guión interactuaba con los sistemas, además, el objetivo de la empresa X era vender la idea, pero en ningún caso llevar dicho proyecto a un entorno interactivo o permitir que aquello sirviera de base para continuar posibles desarrollos de ideas. Aquí entrabamos nosotros.

Nuestra tarea era ir implementando un entorno organizado de todo lo que la empresa X realizaba, llevarlo a un modelo interactivo donde cualquiera pudiera interactuar con el sistema o en donde se pudieran realizar desarrollos a futuro usando de base todo lo que ya existía.

La empresa X con su idea clara de DEMO guiada, optó por el siguiente modelo de desarrollo.

Sin muchas complicaciones. Tenían múltiples funcionalidades concentradas en una misma aplicación WEB construidas sobre MVC. Para cada funcionalidad tenían un único controlador desde el que interactuaban con la base de datos (donde fuera necesario) usando directamente linq2sql.

Nuestro objetivo estaba bien marcado, cambiar todo eso y convertirlo en algo sostenible desde el punto de vista de arquitectura, pero ¿era suficiente? El reconocimiento del trabajo realizado es la base de cualquier cosa que se desee que salga bien, pero en un proyecto como este ¿qué se podía hacer?

Teníamos los siguientes problemas:

  1. Los requerimientos se les pedían directamente a la empresa X
  2. La empresa X siempre iba a estar evolucionando la DEMO con los nuevos requerimientos
  3. Mientras no finalizara la DEMO, nuestro trabajo iba a estar en un segundo plano. :'(

Ni estar en un segundo plano, ni secundar la estrategia de otros (si no es correcta), es una idea que nos agrada en estos casos, más si se trata de tu primer trabajo a un cliente importante. Había que lograr algo más…

Los problemas que podían tener los desarrolladores de la empresa X eran evidentes.  Esos mismos problemas que tan comúnmente nos cuestionamos por estos tiempos. No quieren perder tiempo y desarrollan algo que es solo para mostrar, así que van a toda prisa y se olvidan que sea lo que sea que se construya, si no lo levantas desde una base sólida llegará el momento en que se convierta en algo insostenible.

En una pancarta de publicidad, por poner un ejemplo, el objetivo puede ser solamente mostrar un pedazo de papel. Si usas solo los materiales que permitan mantener en pie la pancarta sin poder ver otros requerimientos a medio y largo plazo, cuando te pidan colocar luminaria sobre la pancarta para que pueda ser vista de noche, tendrás que regresar a la base y apuntalar todo lo que habías hecho para luego poder colocar las luces.

Con este análisis realizado nos trazamos un objetivo más ambicioso:

  1. Crear un entorno ágil de desarrollo: Esto era indispensable, necesitábamos trabajar rápido y con ciclos cortos de evolución. Todos debíamos conocer el trabajo de todos y los cuellos de botella que pudieran afectar el ritmo que deseábamos llevar, debían ser resueltos de inmediato.  (Reuniones en la máquina del café de 15 min hasta tres veces al día)  😛
  2. Una arquitectura organizada que nos permitiera identificar rápidamente los problemas y solucionarlos afectando el menor código posible. Esto a su vez nos llevará a que aplicar nuevos requerimientos sea sencillo y rápido de realizar. Con este objetivo separamos todas las funcionalidades en aplicaciones distintas pero manteniendo MVC y, creamos servicios WCF para cada aplicación. Los servicios WCF se comunicaban con un dominio único que nos permitía desde las distintas aplicaciones, reutilizar la lógica de desarrollada. (Una simple arquitectura de N capas)
  3. Mejoras de performance donde quiera que fuera posible. Este objetivo era menor, pero donde pudiéramos, debíamos hacerlo. El efecto visual es importante de cara a cualquier cliente y muchas veces se trata solamente de variar el orden en que hacemos las cosas.
  4. Integración continua y test unitarios (todo y en todo momento, debía funcionar bien).

La arquitectura (a grandes rasgos) que nos propusimos fue la siguiente:

En principio estar en segundo plano era inevitable. Debíamos estar constantemente chequeando la DEMO para ver las nuevas evoluciones e implementar los cambios sobre nuestra arquitectura pero de manera correcta. Solo podíamos trabajar rápido y bien, el resto era simplemente esperar, darle tiempo al tiempo.

…y el tiempo pasó, y llegó lo que muchos no somos capaces de ver desde un principio. El cambio… Porque siempre, siempre hay cambios…

Aquí cometieron un nuevo error, pero que es muy común en los desarrollos que hacemos a diario. Se pidieron cambios funcionales sobre un proceso determinado pero, realizar las modificaciones sobre lo que ya estaba hecho empezaba a ocupar tiempo y era justo lo que no había. No le puedes decir a un cliente que te demoras 1 mes en  hacer un cambio. Entonces, ¿qué hicieron? La solución fue crear un camino nuevo para dar una respuesta rápida a los cambios. (copy + paste + hacer los cambios) Otra bomba por culpa del tiempo…

Pasó que los cambios no quedaron ahí, y vinieron más y más y se optó por hacer de cada cambio un camino nuevo que cumpliera los requerimientos. El final a esto es previsible, nada cuadraba con nada. Lo que se mostraba en un lugar no tenía que ver con lo que se mostraba en otro. Modificabas algo en un lugar y no se reflejaba en otro. Lograr entonces que el sistema fuera coherente, implicaba modificar todos los nuevos caminos abiertos para los nuevos requerimientos. Cada cambio que se pedía, demoraba más y más y más…

Y mientras del otro lado de la montaña… 🙂  El tiempo nos sirvió para lograr dos cosas:

  1. Llegar a igualar nuestra funcionalidad a la que tenía la empresa X hasta el momento.
  2. Indagar sobre nuevas funcionalidades que no estaban incluidas en la DEMO y desarrollarlas

Al presentar por primera vez nuestro trabajo nos hicieron algunas observaciones y nos pidieron algunos cambios. La respuesta a todos los cambios era un sí. El tiempo para realizarlos 4 días. Era lunes, el viernes se debían presentar para revisión…

La demo guiada que hoy se usa, es nuestra aplicación. 🙂

Pero, pero, pero… no escribo todo esto para decir que lo hemos hecho mejor. Estoy seguro que a muchos de ustedes se les ocurrirían estrategias mejores que la que nos planteamos. Lo dejo escrito, y de ahí el título de este post, para que vean que todo cuanto hacen, por muy DEMO que sea, si no se hace mínimamente bien, a la larga se convierte en una bomba de tiempo contra nosotros mismos. El tiempo que crees ahorrar en un principio no haciendo test, pensando en arquitecturas o soñando con metodologías, puede ser el peor enemigo de lo que estás haciendo.

 Salu2 y suerte con las DEMO… 😉

Publica en Twitter desde el safari del iPhone

Hola,

Hoy ando de inventos…  😉

Resulta que me he instalado la aplicación de Twitter para iPhone porque hace mucho tengo una cuenta en esta red social, pero también hace mucho que la tenía abandonada.

Mirando la aplicación echaba mucho en falta el poder publicar URL directamente desde el navegador del iPhone, pero buscando y buscando me encontré que en los settings de la aplicación para Twitter había una forma de hacer lo que quería.

Las instrucciones a seguir están en esta página:

Era crear un simple bookmark y luego editarlo para dejar solo el javascript. Esto estaba genial pero… las URL las publicaba a tamaño completo y esto para una red que solo permite 140 caracteres por post, es realmente un problema.

Mirando la forma en que lo hacían me di cuenta que lo que hacen es usar javascript para llamar a la aplicación de Twitter y le pasan el URL actual, o sea, el window.location.

La pregunta del millón era: ¿Qué pasa si antes de llamar a tweetie tomo la URL, la convierto  a un formato pequeño (por ejemplo: tinyUrl) y luego se la paso a la aplicación de Twitter? ¿Cómo podría hacer algo así?

Pues bien… me froté las manos y empecé:

Me creo una página HTML sin más, incluyo una referencia a Jquery desde el CDN de Microsoft, y con jQuery en mano, todo es fácil :)))))

Mi página debe:

1- Tomar un parámetro que le pasarían, el cual sería el URL en el que se encuentra navegando el usuario
2-
De alguna forma usar el servicio de TinyURL para convertir la URL a un formato pequeño
3-
y finalmente pasar el resultado a Twitter.

¿Parece simple no? Aquí está el código:

<html>
<head>
    <script type=»text/javascript» src=»http://ajax.microsoft.com/ajax/jQuery/jquery-1.5.1.min.js»></script>
    <script type=»text/javascript»>
        function makeTinyUrl(url)
        {
            $.getJSON(‘http://json-tinyurl.appspot.com/?url=’ + url + ‘&callback=?’,
            function (data)
            {
                window.location = ‘tweetie:’ + data.tinyurl;
            });
        }

        var urlParams = {};
        var e, 
        a = /+/g,  // Regex for replacing addition symbol with a space
        r = /([^&=]+)=?([^&]*)/g,
        d = function (s) { return decodeURIComponent(s.replace(a, » «)); },
        q = window.location.search.substring(1);

        while (e = r.exec(q)) urlParams[d(e[1])] = d(e[2]);

        makeTinyUrl(urlParams[‘tw’]);

    </script>

</head>
<body/>
</html>

Después de publicar mi página HTML en un servidor,  el resto era fácil: Seguir los mismos pasos que dan en Atebits y probar… 🙂

Me cree un bookmark en el safari del iPhone con la siguiente URL:

y WALAAAA!!! Funciona!! :)))))

Quiero aclarar que esta URL solo la dejaré publica por un tiempo para que puedan probar, pero de ninguna forma es parte o se trata de un servicio público. 

Salu2

 

Sirviendo imágenes mediante ActionResult en MVC.

Hola, antes de empezar, desearles a todos un feliz inicio de año y que el trabajo que realicen le haga posible hacer realidad todas las metas que se han trazado.

En el post de hoy vamos a ver cómo podemos servir imágenes mediante un ActionResult en MVC. La práctica de este mecanismo puede ser aplicado a servir imágenes desde una base de datos hacia nuestra WEB o, modificar una imagen que tengamos en el sistema de archivos antes de servirla a nuestra WEB.

No hay truco alguno en esto, simplemente se trata de implementar un nuevo ActionResult que cargue la imagen desde donde queremos y luego la sirva al cliente como un arreglo de byte indicando que el contexto del resultado es del tipo Imagen.

Vamos allá…

Empezamos con el ejemplo más simple. Saquemos la imagen de la base de datos y la servimos a la WEB.

public class PhotoResult : ActionResult
{
  
public override void ExecuteResult(ControllerContext context)
  
{
     
var id = context.HttpContext.Request.QueryString[«id»]; 

     using (var uow = new UnitOfWork())
    
{
        
var photoBytes = (new CustomersDAC(uow).Load(id)).Photo.ToArray();
    
} 

     context.HttpContext.Response.ContentType = «image/png»;
    
context.HttpContext.Response.BinaryWrite(buffer);

    
context.HttpContext.Response.Flush();
 
}
}

Sencillo, implementamos una clase que herede de ActionResult y sobre-escribimos el método ExecuteResult. En este método tomamos un parámetro “id” que nos enviarán por el QueryString y traemos de la base de datos una imagen que tenemos almacenada en forma de arreglo de bytes.

Cuando tenemos el arreglo de bytes lo escribimos en la respuesta que se envía al cliente e indicamos que el tipo de contenido es imagen y su formato es png.

Hasta aquí ya tenemos el ActionResult, ahora solo necesitamos un método en el controlador que nos retorne una instancia de PhotoResult.

public PhotoResult GetPhotoByCustomer()
{
  
return new PhotoResult();

}

Nada más… esto es todo lo que necesitamos para que el controlador ejecute nuestra acción y retorne la imagen al cliente. ¿Cómo lo invocamos?

<img alt=»Your Photo» src<%= Url.Action(«GetPhotoByCustomer?id=1», «Home») %>« />

Cuando el browser hace el GET al servidor para obtener el src de la imagen, en nuestra aplicación esto será traducido a un Request al Método que tenemos dentro del controlador, el cual se encargará de retornarnos la imagen solicitada.

Otra aplicación que mencionamos al inicio del post y que puede tener esta manera de servir imágenes al cliente es cuando queremos modificar una imagen que ya tenemos almacenada en el sistema de archivos antes de mostrarla.

Imaginemos que tenemos una imagen a la cual queremos insertarle un copyright en el momento en que se sirva al cliente y de esta forma ahorrarnos tener que estar editando todas las imágenes que vamos a utilizar antes de subir al servidor.

El cambio para poder hacer lo anterior está solo en el ActionResult que implementamos. El resto de la implementación es exactamente igual.

public class CopyrightImageResult : ActionResult
{
  
private const string Copyright = «Copyright (c) Omar del Valle Rodríguez»; 

   public override void ExecuteResult(ControllerContext context)
  
{
     
var imagePath = context.HttpContext.Server.MapPath(«/images/Photo.PNG»);
     
var mainImage = Image.FromFile(imagePath);
     
var memStream = new MemoryStream(); 

      var fontCopyright = new Font(«Arial», 12);
     
const float xCopyrightPoint = 493.0f;
     
const float yCopyrightPoint = 70.0f; 

      //create graphics from main image
     
using (var g = Graphics.FromImage(mainImage))
     
{
        
g.DrawString(Copyright, fontCopyright, Brushes.Black, xCopyrightPoint, yCopyrightPoint);
        
mainImage.Save(memStream, ImageFormat.Png);
     
} 

      var buffer = memStream.ToArray(); 

      context.HttpContext.Response.ContentType = «image/png»;
     
context.HttpContext.Response.BinaryWrite(buffer);
     
context.HttpContext.Response.Flush();
  
}
}

Lo dicho, cargamos la imagen del sistema de archivos y dibujamos en ella lo que deseamos. Salvamos el resultado a un MemoryStream y lo retornamos como un arreglo de bytes al cliente.

Salu2 y hasta la próxima…

Llamada ajax en MVC usando el $.post de jquery

Hace poco pasé por la necesidad de enviar un formulario al servidor usando ajax en una aplicación MVC. El problema principal que tenía era que el formulario incluía un número “grande” de campos (o no tan grande pero resulta que soy un vago), por lo que no quería pasar el trabajo de tener que convertir todo eso a JSON como parámetros individuales. Tampoco deseaba, evidentemente, tener un método en el controlador al cual le llegaran 5 o más parámetros.

Pues bien… la vista en mi caso estaba diseñada para trabajar con un modelo definido por mí:

public class CustomerModel
{
  
public string UserName { get; set; }
  
public string FirstName { get; set; }
  
public string LastName { get; set; }
  
public string Language { get; set; }

   [DataType(DataType.Password)]
   public string Password { get; set; }
   [DataType(DataType.Password)]
  
public string ConfirmPassword { get; set; }
}

La vista:

<%@ Page Title=»» Language=»C#» MasterPageFile=»~/Views/Shared/Site.Master» Inherits=»System.Web.Mvc.ViewPage<CustomerModel>» %>

Mi formulario:

<% using (Html.BeginForm()) { %>
<
div>
  
<fieldset>
     
<legend>Customer Information</legend>
      <div class=»editor-label»>
        
<%: Html.LabelFor(m => m.FirstName) %>
     
</div>
     
<div class=»editor-field»>
        
<%: Html.TextBoxFor(m => m.FirstName) %>
     
</div>
     
<div class=»editor-label»>
       
<%: Html.LabelFor(m => m.LastName) %>
     
</div>
     
<div class=»editor-field»>
       
<%: Html.TextBoxFor(m => m.LastName) %>
     
</div>
     
<div class=»editor-label»>
       
<%: Html.LabelFor(m => m.UserName) %>
     
</div>
     
<div class=»editor-field»>
       
<%: Html.TextBoxFor(m => m.UserName) %>
     
</div>
     
<div class=»editor-label»>
        
<%: Html.LabelFor(m => m.Password) %>
     
</div>
     
<div class=»editor-field»>
       
<%: Html.PasswordFor(m => m.Password) %>
     
</div>
     
<div class=»editor-label»>
       
<%: Html.LabelFor(m => m.ConfirmPassword) %>
     
</div>
     
<div class=»editor-field»>
       
<%: Html.PasswordFor(m => m.ConfirmPassword) %>
     
</div>
     
<p>
       
<input type=»button» onclick=»uploadCustomerForm()» value=»Register» />

     
</p>
   
</fieldset>
 
</div>
 
<% } %>

La solución ideal para mí era poder pasar un objeto en javascript desde el cliente y que el controlador lo recibiera como el modelo asociado a la vista. Yo quería que el método en mi controlador se viera así:

[AcceptVerbs(HttpVerbs.Post)]
public
ActionResult SaveCustomer(CustomerModel model)
{
  
return Content(string.Format(«This is my content: {0}, {1}»,

             
model.LastName, model.FirstName));
}

Después de mucho andar por los rincones oscuros del mundo Google, hallé una solución limpia, elegante y simple.

Mi script:

<script src=»/Scripts/jquery-1.4.1.min.js» type=»text/javascript»></script>
<
script type=»text/javascript»>
 
function uploadCustomerForm()
 
{
   
var data = $(‘form’).serialize();
   
//Enviar por post
   
$.post(<% =Url.Action(«SaveCustomer») %>, data, insertCallback);
 
}

  function insertCallback(data)
 
{
   
alert(data);
 
}

</script>

Pues sí, así de simple resultó pasar el formulario al controlador y que este recibiera como parámetro el modelo asociado a la vista. Esta instrucción resume todo lo que necesitamos:

var data = $(‘form’).serialize();

Pero, ¿dónde está el truco?

Cada elemento input de mi formulario se crea usando el helper Html.TextBoxFor el cual es asociado a una propiedad del modelo. Esto, si miramos el HTML generado, crea un input cuyo ID Name corresponde con el nombre de la propiedad que, al ser serializado, crea un JSON que hace corresponder ID=valor una representación en el formato clásico de URL (param=valor&m2=valor2&…).

Formulario serializado:

FirstName=aa&LastName=bb&UserName=aa.bb&Password=123&ConfirmPassword=123

Una curiosidad a tener en cuenta es: si miran el formulario podrán ver que he dejado fuera del formulario la propiedad Language de mi modelo, esto lo he hecho con toda intensión para que veamos que no es necesario que nuestro formulario se corresponda 100% con el modelo que tenemos asociado a la vista, pero, sí es necesario que cada ID Name de los elementos del formulario se corresponda con una propiedad llamada exactamente igual a la existente en el modelo.

Con esto… ya tenemos un post por ajax al controlador que recibe como parámetro el modelo asociado a la vista. Esto es posible también hacerlo usando ASP.NET, pero eso lo dejo para un próximo artículo.

😉

Acceso al UI desde un hilo secundario en Silverlight

Todos los que hemos trabajado con aplicaciones Windows y en las cuales hemos necesitado interactuar con el UI desde un hilo secundario sabremos que esto requiere de un tratamiento especial.

Hay una regla de oro cuando trabajamos WinForm e hilos: Con el UI solo se interactúa desde el hilo principal de la aplicación.

Ayer publiqué un artículo sobre un trabajo que vengo haciendo para conectar un servicio y un cliente Silverlight usando Socket. Los sockets usan comunicación asincrónica por lo que el evento de lectura de datos sobre el puerto ocurre en hilos secundarios que son creados por la conexión para notificar a mi aplicación que tenemos información nueva que tratar.

Código que inicializa y conecta el sockets en Silverlight:

DnsEndPoint endPoint = new DnsEndPoint(
       
Application.Current.Host.Source.DnsSafeHost, 4530);

Socket
socket = new Socket(AddressFamily.InterNetwork,
       
SocketType.Stream, ProtocolType.Tcp);

SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.UserToken = socket;
args.RemoteEndPoint = endPoint;
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnSocketConnectCompleted);

socket.ConnectAsync(args);

Aquí podemos ver sin problemas la llamada al método ConnectAsync y la asignación del evento Completed que será lanzado por el socket en el momento en que la conexión o la lectura de datos sean completadas.

La información que me llega desde el servidor es transformada en objetos que son pintados dinámicamente en mi aplicación Silverlight. Esta operación es realizada en el método InitializeExtensionList:

private void OnSocketReceive(object sender, SocketAsyncEventArgs e)
{
  
var data = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
  
//Get initial team data
  
if (_extensions == null)
  
{
     
InitializeExtensionList(data);
  
}

   //Prepare to receive more data
  
Socket socket = (Socket)e.UserToken;
  
socket.ReceiveAsync(e);
}

Pues bien, al intentar ejecutar mi aplicación me encuentro con el siguiente mensaje:

Ummm… Invalid Cross Thread Access: La excepción es UnauthorizedAccessException. El mensaje de error habla por sí solo. Se ha denegado el acceso al UI desde un hilo que no es el principal dentro de mi aplicación.

En aplicaciones Windows esto se resolvía mediante un delegado que me permitiera sincronizar el acceso al UI con el hilo principal de la aplicación.

Ejemplo en Windows Form:

EventHandler m_progress = delegate
{
  
_frmProgress.ShowQuality(userData.ToString());

};

Invoke(m_progress);

El código dentro del delegado interactúa con el UI, la sincronización con el hilo principal se realiza mediante el método Invoque.

Pero… ¿Cómo Silverlight me permitirá hacer esto?

Pues por un lado tenemos la clase Dispatcher, la cual proporciona los servicios que me permiten manejar los elementos de trabajo de un subproceso. En otras palabras, ofrece compatibilidad para ejecutar código en el subproceso de interfaz de usuario de un subproceso que no es de interfaz de usuario. (Just in time! Esto me salva la vida.)

Esta clase tiene un método llamado BeginInvoke el cual recibe como parámetros un delegado y una matriz de valores que se pasan como argumentos (opcional).

Pues nada, que la historia de sincronización entre hilos secundarios y el hilo principal de la interfaz de usuario que tan común es en Windows Form, sobre todo cuando trabajamos con SmartClient, se repite en Silverlight. 😉

La forma correcta para ejecutar mi código sería:

private void OnSocketReceive(object sender, SocketAsyncEventArgs e)
{
  
var data = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
  
//Get initial team data
  
if (_extensions == null)
  
{
     
Dispatcher.BeginInvoke(() => InitializeExtensionList(data));
  
}

   //Prepare to receive more data
  
Socket socket = (Socket)e.UserToken;
  
socket.ReceiveAsync(e);
}

Seguimos 😉