martes, 27 de noviembre de 2012

Limpiar un input file con jQuery

Hace bastante tiempo que no escribo nada porque ando bastante liado, pero me ha parecido bastante interesante compartir esto. El problema surge cuando tras subir un fichero a nuestro servidor queremos limpiar el contenido de nuestro input file desde cliente (por ejemplo, con jQuery). La primera aproximación podría ser esta
$('#fileupload').attr({ value: '' });
Si hemos trabajado algo con web sabemos que esta opción no es válida porque por motivos de seguridad el control es de solo lectura y no podemos modificar su contenido. La solución pasa por volver a crear el control usando el método clone de jQuery.
$fileupload = $('#fileupload');
$fileupload.replaceWith($fileupload.clone(true));
El método clone admite dos parámetros que nos permitirá conservar los valores y los manejadores de los eventos que tengamos definidos en nuestro control o controles hijos.

Espero que les sea útil. Happy coding!

viernes, 2 de noviembre de 2012

C# 5 - Caller Information

Una de las novedades que trae C# en su versión 5.0 es el Caller Information que nos puede ser bastante útil para trazar nuestras aplicaciones. Ahora podemos obtener la siguiente información del método "llamante"
  • CallerFilePathAttribute: Ruta completa del fichero que contiene al "llamante". Hay que tener en cuenta que es la ruta en el momento de la compilación.
  • CallerLineNumberAttribute: Número de linea que contiene la llamada a nuestro método. Line number in the source file at which the method is called.
  • CallerMemberNameAttribute: Método o propiedad del "llamante".
Y como siempre, lo mejor es verlo todo con un ejemplo.
private void button_Click(object sender, EventArgs e)
{
    //...
    NuestroMetodo();
    //...
}

public void NuestroMetodo([CallerFilePath] string sourceFile = "",
    [CallerLineNumber] int lineNumer = 0,
    [CallerMemberName] string memberName = "") {

    string msg = String.Format("{0}: Llamada a nuestro método desde {1}.{3}: line {2} en {4}",
        DateTime.Now.ToString("yyyy-mm-dd HH:MM:ss.fff"),
        Path.GetFileNameWithoutExtension(sourceFile),
        lineNumer,
        memberName,
        sourceFile);

    Debug.WriteLine(msg);
}
Y el resultado de ejecutar este código es el siguiente
2012-41-02 19:11:52.219: Llamada a nuestro método desde Form1.button_Click: line 25 en C:\Users\Sergio\Documents\Visual Studio 2012\Projects\CallerInformationDemo\CallerInformationDemo\Form1.cs
Hay que tener en cuenta que los parámetros a los que le apliquemos los atributos deben ser opcionales. Si no lo hacemos así, el compilador de C# nos los requerirá en la llamada, y los valores que pasemos sobreescribiran los valores por defecto.

No se hasta que punto es práctico decorar todos nuestro métodos con estos atributos pero quizás para determinados momentos nos pueda resultar útil guardar esta información para posteriormente analizarla.

Happy coding!

Más información sobre estos nuevos atributos en la MSDN.
CallerFilePathAttribute
CallerLineNumberAttribute
CallerMemberNameAttribute

domingo, 28 de octubre de 2012

Visual Studio 2012 - Cambiando el idioma del IDE


Para bien o para mal me he acostumbrado a utilizar el Visual Studio en inglés, así que cuando en la versión 2012 solo tenía acceso a la versión española me he sentido un poco perdido a la hora de navegar por los menús y demás opciones del IDE, menos mal que los atajos de teclado son los mismos.

Para cambiar el idioma del IDE tan sólo debemos descargar el Microsoft Visual Studio 2012 Language Pack en el idioma que queramos tener (en nuestro caso ingés) y posteriormente instalarlo. Luego iremos a Herramientas > Opciones y dentro del árbol vamos a Entorno > Configuración internacional y en idioma seleccionamos Inglés. Para que los cambios tengan efecto tendremos que cerrar el volver a abrir el Visual Studio.


Y así tenemos el antes


y el después


Y asunto resuelto, ya tenemos nuestro Visual Studio en inglés.

Happy coding!

sábado, 27 de octubre de 2012

Actualizando a Windows 8 Pro desde Windows 8 Release Preview

Desde ayer está disponible el nuevo Windows 8 para todos los públicos. Pese a que desde hace tiempo estoy usando la Release Preview ya era hora de actualizar el sistema, para entre otras cosas poder instalar el Visual Studio 2012 Pro (versión definitiva). En el momento de realizar la actualización me surgieron dos dudas
  1. Desde la página web donde podías comprar la actualización no decía nada de que se pudiera actualizar desde las versiones "betas" de Windows 8. Sólo se podía actualizar desde Windows XP SP3, Windows Vista y Windows 7.
  2. Si compraba la actualización, ¿qué era lo que realmente estaba comprando?¿una iso?¿una actualización  Y si mañana me compro un SSD y quiero hacer una instalación limpia, ¿puedo reinstalar mi Windows 8?
Con esta dudas lo primero que hice fue intentar acceder a la actualización a través de la propiedades del sistema. Pero tras varios intentos siempre obtenía el mismo error.


El siguiente pasó fue ir a la página de actualización y descargarme un ejecutable se encargaría del proceso de actualización. Así lo hice y de esta manera todo fue correcto. Nada más arrancar el "actualizador" éste se tomará su tiempo para analizar tu sistema actual e informarte de los problemas que puedes tener con la aplicaciones instaladas a la hora de actualizar tu sistema. En mi caso solo tendría problemas con el Daemon Tools Lite que uso para montar imágenes, o sea, un problema menor teniendo en cuenta que el Windows ya trae este comportamiento de serie. Tras esto podemos realizar la compra de la actualización





Tras realizar el pago se iniciará la descarga de la actualización. Una vez terminada la descarga nos preguntará que queremos hacer, si instalarla o por ejemplo crear un medio de instalación. En mi caso seleccione está opción, y cree una ISO que yo posteriormente quemé en un DVD y desde el que ahora mismo estoy realizando la instalación de Windows 8 sin problemas. Así que, pese a que estamos comprando una actualización tenemos una ISO que podemos guardar para posteriormente realizar otra instalación.


Notas
  • Desde esta página https://www.mswos.com/ podemos reiniciar la descarga introduciendo algunos datos como el número de pedido y el apellido y correo electrónico que usamos en la compra.
  • La nueva instalación me ha respetado completamente el arranque dual que tenía con Windows 7.

Happy coding!


miércoles, 24 de octubre de 2012

Atajos de teclado en Windows 8

A medida que han ido pasando las semanas usando Windows 8 me he ido acostumbrando a usar los atajos de teclado. Buscando por internet encontré un listado que puede ser útil.


Los más que uso son

  • WIN + Q: Para buscar aplicaciones.
  • WIN + I: Panel de opciones para luego poder apagar o suspender el equipo.
  • WIN + D: Ir al escritorio (esta no es de Windows 8).
  • WIN + E: Ir al explorador de Windows (tampoco es exclusiva de Windows 8).
Os podéis descargar la imagen desde aquí.

miércoles, 17 de octubre de 2012

Evento. Lanzamiento de Visual Studio 2012

Después del éxito del Megathon de Windows 8 organizado por el grupo TenerifeDev para el próximo 9 de noviembre hemos preparado unas píldoras de sesiones para enseñaros las múltiples novedades que nos trae la nueva versión del Visual Studio (Visual Studio 2012). Y digo hemos, porque esta vez me uno al grupo para dar una de las píldoras que se darán. La idea surge siguiendo la estela del evento que van a celebrar en Madrid la gente de MadridDotNet,


Más concretamente daré una charla sobre los nuevos modificadores async y await que vienen con el Framework .NET4.5. Si quieres saber más te recomiendo que asistas al evento, aunque para ir abriendo boca os puedo decir que mediante el uso de async se puede llamar a métodos asíncronos sin definir continuaciones o dividir el código en varios métodos o expresiones lambda de una manera muy simple y quedando un código muy fácil de leer. Después de una pequeña introducción teórica veremos algunos ejemplos de código donde analizaremos como eran las cosas "antes" y como son "ahora" con estos nuevos modificadores.

Para registrarte al evento puedes hacer click en el siguiente enlace.

Detalles del evento
9 de noviembre, en las Aulas de la Fundación Empresa Universidad de La Laguna a la cual hay que agradecer su desinteresada colaboración en este tipo de eventos, de 17.00 a 20.00. Si eres desarrollador o futuro desarrollador, no te puedes perder la siguiente agenda:
¡Nos vemos en el evento!

No quiero terminar sin agradecer a Alberto DíazSantiago PorrasJosé Fortes y David Rodríguez la oportunidad dar una de las píldoras.

martes, 18 de septiembre de 2012

Utilizar un número indeterminado de parámetros en C#

Tal y como hace el método Format de la clase String hoy he necesitado hacer una función que utilice un número indeterminado, bueno en realidad tres o 4, de parámetros, pero no me apetecía crear 3, 4 o 5 métodos  iguales con llamadas de unos a otros. La solución es bien simple y para eso usaremos una característica que nos da C#. Para demostrar su funcionamiento haremos una función que sumará un número indeterminado de número de enteros
public int Suma(params int[] values)
{
 int suma = 0;
 for (int i = 0; i < values.Length; i++)
  suma += values[i];
 return suma;
}
Bastante fácil, ¿verdad?

Happy coding!

jueves, 30 de agosto de 2012

Haciendo test en javascript con jasmine

Antes de irme de vacaciones asistí a unas charlas denominadas #jsweek dadas por el grupo @agileCanarias. La charlas fueron impartidas por @ydarias y por @axelhzf, y se tocaron temas tan divertidos como los WTF de javascript, CoffeeScript y Backbone.

Bien, en la charla de introducción a javascript aprendí a usar jasmine, que no es otra cosa que un framework para hacer test unitarios en javascript. A medida que escribíamos los test para la kata fizzbuzz me di cuenta que podría aplicar este framework a mi método de comparación de objetos que expliqué en mi anterior post (Comparando objetos en javascript)

Sin ser un experto, o más bien, considerándome un neófito en esto de los test unitarios, lo primero que debemos hacer es bajarnos el framework desde su página web. Una vez descargado y descomprimido veremos que tenemos la siguiente estructura
  • Un fichero SpecRunner.html desde donde se ejecutaran los test que definamos.
  • Una carpeta lib donde esta el propio framework y donde en principio no tenemos que tocar nada.
  • Una carpeta spec donde irán los test que queremos ejecutar.
  • Una carpeta src donde irá el código que queremos probrar.
En mi caso he creado un proyecto llamado HelperJS con un fichero prototypes.js donde está el código descrito en el post anterior y una carpeta test que tiene la estructura anteriormente descrita. Ahora lo que haremos será abrir el fichero SpectRunner.html y añadiremos las referencias a los ficheros de test y ded código que queremos probar.
<!-- include spec files here... -->
<script type="text/javascript" src="spec/prototypesSpec.js"></script>

<!-- include source files here... -->
<script type="text/javascript" src="../prototypes.js"></script>
Si abrimos la página SpecRunner.html en el navegador obtendremos una página vacia, por lo que lo siguiente será escribir los test en el fichero prototypesSpec.js. Siguiendo un poco la métodología TDD (y repito que soy un novato total en el tema) lo normal es escribir los test de lo más simple a lo más complejo (aunque en mi caso el código ya está escrito). Basándome en esto lo más simple es escribir un test para cuando el segundo objeto es null o undefined. Con esto podemos escribir nuestro primeros test de la siguiente manera
describe("Object.prototype.equals", function() {
 it("El objeto a comparar es null", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = null;

  expect(u1.equals(u2)).toBe(false);
 });

 it("El objeto a comparar es undefined", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = undefined;

  expect(u1.equals(u2)).toBe(false);
 });
});
Como vemos el código es bastante fácil de entender. El método describe se usar para definir un grupo de test (u otro grupo) y le pasamos una función donde se definen los test. Para definir un test usamos el método it, al que le pasamos una descripción del test y un función donde se ejecuta el test gracias a expect donde indicamos lo que queremos probar y el valor que debe tener. Si todo ha ido bien al recargar la página SpecRunner.html debemos obtener algo como esto


Con esto claro, ya podemos escribir el resto de test en lo que comprobamos distintas posibilidades que se pueden dar.
describe("Object.prototype.equals", function() {
 it("El objeto a comparar es null", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = null;

  expect(u1.equals(u2)).toBe(false);
 });

 it("El objeto a comparar es undefined", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = undefined;

  expect(u1.equals(u2)).toBe(false);
 });

 it("Distinto numero de propiedades", function() {
  var u1= {prop1 : "value1", prop2: 2};  
  var u2= {prop1 : "value1", prop2: 2, prop3: 3};  

  expect(u1.equals(u2)).toBe(false);
 });

 it("Mismas propiedades pero con distintos valores", function() {
  var u1= {prop1 : "value1", prop2: 2};  
  var u2= {prop1 : "value1", prop2: 3};  

  expect(u1.equals(u2)).toBe(false);
 }); 

 it("Mismo numero de propiedades pero con nombres distintos", function() {
  var u1= {prop1 : "value1", prop2: 2};  
  var u2= {prop1 : "value1", prop3: 3};  

  expect(u1.equals(u2)).toBe(false);
 }); 
  
 it("Dos objetos simples iguales", function() {
  var u1 = {prop1: "1", prop2: 2};
  var u2 = {prop1: "1", prop2: 2};

  expect(u1.equals(u2)).toBe(true);
 });

 it("Dos objetos compuestos distintos", function() {
  var u1 = {prop1: "1", prop2: 2, prop3: { prop4: 4}};
  var u2 = {prop1: "1", prop2: 2, prop3: { prop5: 5}};

  expect(u1.equals(u2)).toBe(false);
 });

 it("Dos objetos compuestos iguales", function() {
  var u1 = {prop1: "1", prop2: 2, prop3: { prop4: 4}};
  var u2 = {prop1: "1", prop2: 2, prop3: { prop4: 4}};

  expect(u1.equals(u2)).toBe(true);
 });
});
Obteniendo la siguiente salida


Como vemos es bastante fácil escribir test simples para nuestro código javascript. Si estás interesado en probar otros framework de este tipo también está QUnit que por lo que me han comentado también está bastante bien.

Todo esta código espero subirlo próximamente a GitHub.

Happy coding!

viernes, 10 de agosto de 2012

Comparando objetos en javascript

La verdad es que por muchas horas que invierta en programar en javascript y en leer esos pequeños detalles que tiene y que pueden volverte loco un par de horas no paro de sorprenderme al ver algunas cosas. La última sin ir más lejos es la siguiente y la mostraré con un simple trozo de código.
var u1 = {prop1 : 1, prop2: "value2"};
var u2 = {prop1 : 1, prop2: "value2"};
console.log(u1 == u2); 
console.log(u1 === u2);
Simplemente estamos declarando dos objetos y los estamos comparando. Como vemos ambos objetos tienes las mismas propiedades (prop1 y prop2) y los mismos valores en dichas propiedades, prop1 vale 1 y prop2 vale "value2". Las siguientes lineas muestran por la consola el resultado de comparar ambos objetos. Supongo que la respuesta lógica sería pensar que algunas de las dos comparaciones debería devolver true. ¿Verdad?, pues no, ambas comparaciones devuelve false.

Si el objeto lo declaramos de otra manera menos que el efecto es el mismo
function Foo(p1,p2) {
    this.prop1 = p1;
    this.prop2 = p2;    
}

var u1 = new Foo(1, "value2");
var u2 = new Foo(1, "value2");

console.log(u1 == u2);  // false
console.log(u1 === u2); // false
Vemos que en ese caso el comportamiento similar así que podemos descartar que este comportamiento sea debido a como hemos declarado nuestros objetos.

Después de pensar un poco en el asunto y necesitando una función que me comparara dos objetos busqué la forma de hacer dicha comparación. Lo primero que determiné es que son para mi dos objetos iguales, y para mi negocio son aquellos objetos cuyas propiedades (solo propiedades y no funciones) sean iguales. O sea que esta comparación sería correcta
function Foo(p1,p2) {
    this.prop1 = p1;
    this.prop2 = p2;
    this.bar = function() {
        // do operation
    }        
}

var u1 = new Foo(1, "value2");
var u2 = new Foo(1, "value2");

console.log(u1 == u2);  // false
console.log(u1 === u2); // false
Con eso claro lo único que tenemos que hacer es recorrer las propiedades de los objetos implicados e ir comparando valores. Recorrer las propiedades de un objeto es bastante fácil pero puede darnos algún problema si no tenemos algunas cosas en cuenta. En concreto el principal problema es que dependiendo del contexto donde recorramos las propiedades del objeto podemos obtener las propiedades heredadas de dicho objeto, por lo que para evitarlo debemos usar el método hasOwnProperty, que nos asegura que esa propiedad es del objeto en cuestión. En nuestro ejemplo
function Foo(p1,p2) {
    this.prop1 = p1;
    this.prop2 = p2;
    this.func1 = function() {
        // do operation
    }        
}

var u1 = new Foo(1, "value2");
for (var p in u1)
{
  if (u1.hasOwnProperty(p))
    console.log(p);        
}
Obtendríamos esta salida
prop1
prop2
bar
Con esto claro ya podemos intentar hacer nuestro comparador de objetos. La primera versión que se nos viene a la mente es hacer algo así
function equals(p1, p2)
{
    // Comparamos los objetos
}
Esta alternativa no es mala, pero pienso que es más elegante extender el tipo object y añadir el método equals, para poder hacer algo así
p1.equals(p2);
Esto es bastante fácil en javascript y el esqueleto sería el siguiente
Object.prototype.equals = function(x)
{
  // Comparamos los objetos 
}
Al principio del método podemos hacer algunas comparaciones básicas como si x no está definido o si los objetos a comparar tienen el mismo número de propiedades. Esta útlima comparación se hace a través del método keys que desgraciadamente no está disponible en todos los navegadores (se puede consultar su disponibilidad aquí). Con esto, nuestro método ya va tomando cuerpo y sería de la siguiente forma
Object.prototype.equals = function(x)
{   
    if (x === null || x === undefined) 
      return false;
            
    if (Object.keys(this).length != Object.keys(x).length)
      return false;
       
    // Comparamos los objetos                             

    return true;                
}
Con esto ya lo único que nos queda es recorrer las propiedades del objeto de origen e ir buscando sus homólogas para luego comparar su valor. En estas comparaciones veremos de que tipo es la propiedad, para ver si comparamos directamente sus valores, volvernos a llamar al método equals en caso de ser un objeto o devolvemos false en caso que sea una función. Con esto nuestro método equals quedaría de la siguiente manera
Object.prototype.equals = function(x)
{   
    if (x === null || x === undefined) 
        return false;
            
    if (Object.keys(this).length != Object.keys(x).length) return false;
                                   
    for (var p in this)
    {
        // Evitamos navegar por las propiedades "heredadas"
        if (this.hasOwnProperty(p)) {
            // No es una propiedad de x                 
            if (!x.hasOwnProperty(p)) return false;             
            switch(typeof(this[p])) {
                case 'function': 
                    // No admitimos objetos con funciones
                    return false;
                case 'object': 
                    // Comparamos los objetos
                    if (!this[p].equals(x[p]))
                         return false;  
                    break; 
                default:             
                    // Las propiedades tienes valores distintos
                    if (this[p] !== x[p])
                        return false;
                    break;
            }                        
        }
    }

    return true;                
}
Para probar este código de manera rudimentaria he hecho este código y lo he lanzado en jsFiddle y los resultado obtenidos son los esperados
var u1= {prop1 : "value1", prop2: "value2"};
var u2= {prop1 : "value1", prop2: "value2"};
console.log('u1 equals u2: ' + u1.equals(u2));

var v1= {prop1 : "value1", prop2: "value2"};
var v2= {prop1 : "value1", prop2: "value2", prop3: "value3"};
console.log('v1 equals v2: ' + v1.equals(v2));    

var w1= {prop1 : "value1", prop2: "value2"};
var w2= {prop1 : "value1", prop2: "value3"};
console.log('w1 equals w2: ' + w1.equals(w2)); 

var x1= {prop1 : "value1", prop2: "value2"};
var x2= {prop1 : "value1", prop3: "value2"};
console.log('x1 equals x2: ' + x1.equals(x2));

var y1= {prop1 : "value1", prop2: { prop3: "value3"}};
var y2= {prop1 : "value1", prop2: { prop4: "value4"}};
console.log('y1 equals y2: ' + y1.equals(y2));

var z1= {prop1 : "value1", prop2: { prop3: "value3"}};
var z2= {prop1 : "value1", prop2: { prop3: "value3"}};
console.log('z1 equals z2: ' + z1.equals(z2));
Puedes probar este código desde aquí

Se que esta no es la manera más óptima de probar el código y para esto existen framework de javascript como Jasmine o QUnit pero esta parte la dejaré para otro post.

En definitiva hemos visto que hay que estar atentos a muchos comportamientos que tiene javascript ya que algo tan simple como una comparación de objetos puede ser una vez más una tarea complicada.

Happy coding!

martes, 7 de agosto de 2012

Los operadores de comparación en javascript

Desde hace algún tiempo cada vez invierto más horas de mi jornada laboral en programar en javascript. A medida que vas programando en este lenguaje te vas dando cuenta de las muchas peculiaridades que tiene, y que te puede arruinar una jornada laboral.

Para los que vienen de programar en lenguajes como C# este tipo de sentencias son de lo más normales
if (a == b) { 
  // a y b son iguales
}
El problema está en que javascript las cosas no son como nosotros estamos acostumbrados que sean y este comparador nos pueden dar algún que otro quebradero de cabeza y más teniendo en cuenta que también tenemos un triple comparador, si como lo oyes, tenemos un triple comparador que se escribe ===.

Entonces, ¿cuál es la diferencia entre == y ===? Pues bien, el doble comparador por decirlo de una manera hace una comparación por valor y en caso que los tipos no sean igual javascript hace una coerción de tipos. El triple comparador, al contrario que el doble comparador, por decirlo de alguna manera fuerza la igualdad de tipos y del valor que estamos comparando.

Sabiendo esto, tenemos que estar atento a la hora de comparar variables porque javascript puede resolver la comparación de la manera que nosotros no esperamos.

Algunos ejemplos para que todo quede más claro
1 == 1            // true como era de esperar
1 == "1"          // true, se convierte la cadena de texto a numero
null == undefined // true
1 == true         // true
"" == false       // true
'\n' == false     // true, el '\n' se interpreta como la cadena vacía
"" == 0           // true
'\n' == 0         // true
Como vemos en todas las comparaciones (salvo la primera) esperaríamos que javascript nos devolviera false, sin embargo nos devuelve true. Para salvar esto deberíamos usar el triple comparador.
1 === 1            // sigue siendo true
1 === "1"          // false
null === undefined // false
1 === true         // false
"" === false       // false
'\n' === false     // false
"" === 0           // false
'\n' === 0         // false
De igual forma que tenemos == y ===, también tenemos != y !== cuyo comportamiento es análogo.

Otras comparaciones curiosas pero menos comunes son
NaN == NaN  // false, NaN es Not a Number y no se puede comparar
NaN === NaN // false
1.0 == 1    // true
1.0 === 1   // true, para javascript ambos son de tipo numeric
La coerción de tipos puede ser algo realmente frustrante y que nos puede volver locos un par horas, pero que nos puede venir bastante bien en algunas situaciones por lo que lo mejor es estar seguro de lo que estamos haciendo en cada momento.

Happy coding!

lunes, 6 de agosto de 2012

Introducción a Knockout (VIII) - obsersable computed y binding event

Con los binding que trae knockout de fábrica debería ser más que suficiente para la mayoría de los proyectos en los que usemos knockout. Pese a ésto knockout nos brinda la forma de poder extender estos comportamientos predefinidos para poder tener un control total sobre nuestra vista y así no tener prácticamente ninguna limitación.

Computed Observables
Dentro de los observables que nos da knockout tenemos los computed observables (prefiero no traducirlo). Son funciones, que depende de uno o más observables y que se actualizan automáticamente cuando una de sus dependencias cambia. Típicamente se usan para información que se muestra en solo lectura aunque como veremos más adelante también los computed observables pueden ser de escritura y ellos a su vez puede actualizar valores.

Supongamos esta vista
<p>Nombre: <input type="text" data-bind="value: firstname" /></p>
<p>Apellidos: <input type="text" data-bind="value: lastname" /></p>
<p>Nombre completo: <label data-bind="text: name"></p>
Y este modelo
function ViewModel(model) {  
    var self = this;  
  
    self.firstname = ko.observable('');  
    self.lastname = ko.observable('');  
    self.name = ko.computed(function() {
        if (self.firstname() == '' || self.lastname() == '') return '';
         return self.lastname() + ', ' + self.firstname();
    });
}  

var viewModel = new ViewModel();  
ko.applyBindings(viewModel);​
Como vemos establecemos dos observables sobre firstname y lastname. También definimos observable computed que actualiza la propiedad name. Esta función se lanzará cada vez que la propiedades lastname y firstname cambien. Lo realmente maravilloso es que la función detecta a que propiedades debe detectar los cambios sin que nosotros debamos hacer nada más que usarlas en el cuerpo de la función.

Podemos probar este ejemplo en el siguiente enlace.

Como comentamos antes, los computed observables también pueden ser de escritura y ellos actualizar determinados valores. He de reconocer que esto no suele ser muy común pero puede que en algún momento nos sea útil. Para hacer un computed observables de lectura y escritura en el ejemplo anterior cambiaremos la vista
<p>Nombre: <input type="text" data-bind="value: firstname" /></p>
<p>Apellidos: <input type="text" data-bind="value: lastname" /></p>
<p>Nombre completo: <input type="text" data-bind="value: name"></p>
y el modelo de la siguiente manera
function ViewModel(model) {  
    var self = this;  
  
    self.firstname = ko.observable('');  
    self.lastname = ko.observable('');  
    self.name = ko.computed({
        read: function() {
            if (self.firstname() == '' || self.lastname() == '') return '';
                return self.lastname() + ', ' + self.firstname();
        },
        write: function(value) {
            var index = value.lastIndexOf(", ");
            if (index > 0) 
            { 
                self.firstname(value.substring(index + 2));
                self.lastname(value.substring(0, index));
            }
        }
    });
}  

var viewModel = new ViewModel();  
ko.applyBindings(viewModel);​
Tal y como hicimos antes, si actualizamos el nombre y los apellidos automáticamente se actualizará el campo del nombre del completo. La salvedad en este caso, es que si actualizamos el nombre completo nosotros con el formato apellidos, nombre, se actualizarán los campos nombre y apellidos.

Podemos probar este ejemplo en el siguiente enlace.

Binding Event
Otra de las posibilidades que nos da knockout es trabajar directamente con los eventos que tienes javascript, pese a que ya tenemos algunos bindings que trabajan con ellos como puede ser el binding click.
Por ejemplo, si definimos la siguiente vista
<div>
    <input type="text" data-bind="value: message, event: { keyup: onkeyup }" />
    <label data-bind="text: status" ></label>
</div>​
y el siguiente modelo
function ViewModel(model) {  
    var self = this; 

    self.message = ko.observable('');
    self.status = ko.observable('Has escrito 0 caracteres...');
  
    self.onkeyup = function(data, event) {
        self.status('Has escrito ' + event.target.value.length + ' caracteres...');           
        return true;
    }
}  
ko.applyBindings(new ViewModel());
En este ejemplo estamos enganchándonos al evento keyup de un textbox y actualizamos un label con la información del número de caracteres que hemos introducido en el textbox.

Podemos probar este ejemplo en el siguiente enlace.

Como vemos, knoutout es bastante versátil y prácticamente podemos hacer lo que queramos. En el próximo artículo veremos como hacer nuestros propios bindings que también nos pueden ser útiles en algunos contextos.

Happy coding!

martes, 31 de julio de 2012

GridView, mostrando datos en tiempo de diseño

Algo que puede resulta molesto a la hora de trabajar con el GridView es que no vemos el aspecto que éste tendrá hasta que no ejecutamos la aplicación. Esto puede suponer una gran perdida de tiempo si estamos en una fase en la que estamos "depurando" nuestra UI.

Para mostrar datos en el diseñador debemos declararlos en el XAML en vez a través de la propiedad DataContext. Esto es así porque el diseñador parsea el XAML pero no ejecuta el code-behind. Existen varias alternativas para conseguir esto, así que vamos a ver una de ellas. Lo primero que haremos será definir nuestro origen de datos
public class MenuModel
{
    public int IdMenu { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

public class MenuModelList : List<MenuModel>
{
    public MenuModelList()
    {
        this.Add(new MenuModel() { IdMenu = 1, Name = "Name 1", Description = "Description 1" });
        this.Add(new MenuModel() { IdMenu = 2, Name = "Name 2", Description = "Description 2" });
    }
}
Después declararemos este objeto como un recurso para que pueda referenciado por otros elementos de la siguiente manera
<Page.Resources>
    <local:MenuModelList x:Key="MenuListData"/>
    <CollectionViewSource x:Name="MenuListResource"
        Source="{StaticResource MenuListData}"/>        
</Page.Resources>
Y lo referenciaremos desde nuestro GridView de la siguiente forma
<GridView x:Name="GridViewMenu"
            HorizontalAlignment="Left" 
            Margin="19,70,0,0" 
            Grid.Row="1" 
            VerticalAlignment="Top" 
            SelectionMode="None"
            IsItemClickEnabled="True"                                                       
            ItemsSource="{Binding Source={StaticResource MenuListResource}}">

    <!-- Resto de información del GridView -->
</GridView>
De esta manera veremos nuestro GridView en tiempo de diseño de la siguiente manera

GridView en tiempo de diseño

El único inconveniente del modelo planteado anteriormente es que esos datos serán los mismos que se usarán cuando nuestra aplicación esté en ejecución. Si queremos usar otros datos en ejecución podemos optar por cambiar el origen de datos en el constructor de nuestro modelo en base a si estamos en tiempo de diseño o en tiempo de ejecución. Para conseguir esto podemos hacer los siguiente
public class MenuModelList : List<MenuModel> {
    public MenuModelList()
    {
        if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
            GetSampleData();
        else
            GetRealData();
    }

    private void GetSampleData()
    {
        this.Add(new MenuModel() { IdMenu = 1, Name = "Name 1", Description = "Description 1" });
        this.Add(new MenuModel() { IdMenu = 2, Name = "Name 2", Description = "Description 2" });
    }

    private void GetRealData()
    {
        this.Add(new MenuModel() { IdMenu = 1, Name = "Elemento 1", Description = "Descripción del elemento 1" });
        this.Add(new MenuModel() { IdMenu = 2, Name = "Elemento 2", Description = "Descripción del elemento 2" });
    }
}
Si ejecutamos ahora nuestra aplicaciones veremos que obtenemos otros datos distintos a los que obteníamos en tiempo de diseño.

GridView en tiempo de ejecución

Como vemos es relativamente fácil mostrar información en nuestros GridView en tiempo de ejecución lo cual hace que el diseño de nuestra aplicación sea más fácil de llevar a cabo porque evitaremos infinidad de ejecuciones innecesarias.

Happy coding!

viernes, 27 de julio de 2012

Diferencias entre DataContext y ItemsSource en Metro

Para aquellos que no tengamos demasiada experiencia en WPF o Silverlight el bindeo de datos puede ser un poco confuso teniendo en cuenta que parece que se puede hacer de dos maneras distintas, tanto a través de la propiedad DataContext como de la propiedad ItemsSource. Pese a que puedan parecer propiedades idénticas nada más lejos de la realidad ya que ambas propiedades tienen un propósito bien distinto.

DataContext es una propiedad general de todos los descendientes de FrameworkElement. Es heredada a de padres a hijos y puede ser usada como origen de datos para el DataBinding.

ItemsSource es una propiedad que identifica la generación de elementos de los controles que derivan de ItemsControl. Cuando establecemos esta propiedad a través de DataBinding o vía código el control generará los elementos internamente. Estableciendo la propiedad DataContext en un ItemsControls no provocaremos el mismo efecto.

Bien, pero como no sólo de teoría vive el desarrollador vamos a ver esto en un ejemplo. Imaginemos que tenemos esta clase
public class MenuModel
{
    public int IdMenu { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}
Y que inicializamos una lista de elementos de la siguiente manera
List<MenuModel> items = new List<MenuModel>();
items.Add(new MenuModel() { IdMenu = 1, Name = "Elemento 1", Description = "Descripción del elemento 1" });
items.Add(new MenuModel() { IdMenu = 2, Name = "Elemento 2", Description = "Descripción del elemento 2" });
Bien con esto podremos hacer lo siguiente sobre un GridView
GridViewMenu.ItemsSource = items;
O sea, aplicaremos como origen de datos la colección de elementos única y exclusivamente al GridView. El resultado será este

GridView

Bien, ahora cambiaremos la llamada a ItemsSource por DataContext y veremos que ocurre. Correcto, lo que ocurre es que no se ha generado el GridView y eso porque el ItemsSource si lanza la generación del control pero el DataContext no. Para que se genere el control debemos modificar el DataBind del GridView  de la siguiente manera
<GridView x:Name="GridViewMenu"
            HorizontalAlignment="Left"
            Margin="19,70,0,0"
            Grid.Row="1"
            VerticalAlignment="Top"
            SelectionMode="None"
            IsItemClickEnabled="True"
            ItemTemplate="{StaticResource itemTemplate}"
            ItemsSource="{Binding}">

Bien, pero con DataContext podemos hacer algunas cosas más como hemos comentado antes. Vamos a crear un modelo que tenga nuestra lista de elemento y un texto y vamos a ver como podemos hacer el bindeo de datos de una manera muy simple.
public class MainPageModel
{
    public string Titulo { get; set; }
    public List<MenuModel> Items { get; set; }

    public MainPageModel()
    {
        this.Titulo = "Mi título";

        Items = new List<MenuModel>();
        Items.Add(new MenuModel() { IdMenu = 1, Name = "Elemento 1", Description = "Descripción del elemento 1" });
        Items.Add(new MenuModel() { IdMenu = 2, Name = "Elemento 2", Description = "Descripción del elemento 2" });
    }
}
Como hemos dicho antes DataContext es una propiedad que se programa por toda la jerarquía de hijos, así que la asignaremos al DataContext de la página
this.DataContext = model;
Y en el diseñador pondremos también un TextBox de la siguiente manera
<TextBlock HorizontalAlignment="Left" Height="24" Margin="18,16,0,0" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Titulo}" FontSize="24" VerticalAlignment="Top" Width="339"/>
<GridView x:Name="GridViewMenu"
            HorizontalAlignment="Left"
            Margin="19,70,0,0"
            Grid.Row="1"
            VerticalAlignment="Top"
            SelectionMode="None"
            IsItemClickEnabled="True"
            ItemTemplate="{StaticResource itemTemplate}"
            ItemsSource="{Binding Items}">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
El resultado de esto es el siguiente

GridView

En lineas generales podemos decir que usaremos ItemsSource si solo vamos a enlazar un ItemsControl con un único origen de datos y si tenemos varios elementos que van consumir nuestro origen de datos usaremos DataContext.

Nota: En el fichero StandardStyles.xaml tengo definida la siguiente Template para definir es aspecto del GridView
<!-- DataTemplates -->
<DataTemplate x:Key="itemTemplate">
    <Grid Background="DarkGray" Width="250" Height="250">
        <StackPanel Orientation="Vertical" VerticalAlignment="Bottom" Margin="0,0,0,10">
            <TextBlock Text="{Binding Name}" 
                    FontSize="24"  Margin="10,0,0,0" 
                    TextTrimming="WordEllipsis" TextWrapping="Wrap" 
                    HorizontalAlignment="Left"/>
            <TextBlock Text="{Binding Description}" 
                    FontSize="12" Margin="10,0,0,0" 
                    TextTrimming="WordEllipsis" TextWrapping="Wrap" 
                    HorizontalAlignment="Left"/>
        </StackPanel>
    </Grid>
</DataTemplate>

Happy coding!

jueves, 26 de julio de 2012

Introducción a Knockout (VII) - La propiedad $index

El otro día estaba revisando la documentación de binding foreach de knockout cuando recordé que una de las novedades que había traído la versión 2.1.0 era la inclusión de la propiedad $index dentro del contexto foreach. Pensando que utilidad podría tener dentro de una aplicación real y que no fuera la de simplemente mostrar un índice ya que eso lo podemos tener usando <ol>.

Pensando un poco se me ocurrió un ejemplo donde nos podría ser útil esta nueva propiedad, así que supongamos que tenemos una colección de elementos de este tipo
public class Item
{
 public int IdItem { get; set; }
 public string Description { get; set; }
 public int Quantity { get; set; }
}
Esta colección de elementos se la tenemos que presentar al usuario y este debe escribir las cantidades que quiere para cada Item, y enviarla de nuevo al servidor. Se podría ver como un versión muy reducida de un carrito de la compra, donde tenemos los elementos que queremos comprar y podemos modificar la cantidad de elementos. Bien, para mostrar esta información y para simplificar el ejemplo he creado la siguiente modelo y acciones

Modelo
public class Model
{
 public List<Item> Items { get; set; }
}
Acciones
public ActionResult Index()
{
 Model model = new Model();
 FillModel(model);

 return View(model);
}

[HttpPost()]
public ActionResult Index(Model model)
{
 return RedirectToAction("Index");
}

private void FillModel(Model model)
{
 model.Items = new List<Item>();
 for (int i = 1; i <= 10; i++)
  model.Items.Add(new Item() { IdItem = i, Description = string.Format("Item{0}", i), Quantity = 0 });
}
Vista
<h2>Items</h2>
@using (Html.BeginForm())
{ 
 for(int i = 0; i < Model.Items.Count; i++)
 {
  <div>
   @Html.HiddenFor(m => Model.Items[i].IdItem)
   @Html.HiddenFor(m => Model.Items[i].Description)
   @Model.Items[i].Description
   @Html.TextBoxFor(m => Model.Items[i].Quantity)
  </div>
 }
 <input type="submit" value="Enviar" />
}
El aspecto de este formulario sería el siguiente

Vista

Bien, si modificamos alguna de las cantidades y le damos a enviar, obtendremos esto en la controladora

Post

Como vemos el valor introducido por el usuario (10)  ha sido "bindeado" en nuestro modelo sin problemas. Bien, ahora supongamos que queremos hacer lo mismo pero usando knockout. Para eso, debemos modificar ligeramente la vista de la siguiente manera.
@using (Html.BeginForm())
{ 
 <!-- ko foreach: items -->
 <div>
  <input type="hidden" data-bind="value: IdItem"  />
  <input type="hidden" data-bind="value: Description"  />
  <span data-bind="text: Description"></span>
  <input type="text" data-bind="value: Quantity"  />
 </div>
 <!-- /ko -->
 <input type="submit" value="Enviar" />
}

<script type="text/javascript">
 $(document).ready(function () {
  function ViewModel(model) {
   var self = this;

   self.items = ko.observableArray(model.Items);
  }
  var viewModel = new ViewModel(@Html.Raw(Json.Encode(Model)));
  ko.applyBindings(viewModel);
 });
</script>
Con esto veremos que nuestra vista es igual a la obtenida anteriormente, pero al enviar el form nos daremos cuenta que nuestro modelo no se "bindea" correctamente.


Si sabemos como funciona el bind de ASP.NET MVC veremos que este error es lógico ya que los elementos que estamos poniendo en nuestra vista no tienen el atributo name definido, pero además hay que tener en cuenta que estamos intentando "bindear" una colección por lo que tendremos que especificar el índice que ocupa el elemento en la colección. Para esto es para lo que viene de maravilla el uso de la propiedad $index dentro del contexto foreach (no es que antes no se pudiera hacer, sino que era más complicado). Con esto la vista quedaría de la siguiente manera
<!-- ko foreach: items -->
<div>
 <input type="hidden" data-bind="value: IdItem, attr: {name: 'Items['+$index()+'].IdItem'}"  />
 <input type="hidden" data-bind="value: Description, attr: {name: 'Items['+$index()+'].Description'}"  />
 <span data-bind="text: Description"></span>
 <input type="text" data-bind="value: Quantity, attr: {name: 'Items['+$index()+'].Quantity'}"  />
</div>
<!-- /ko -->
Esto generaría el siguiente código html que vemos que cumple con lo dicho anteriormente

Vista HTML

Y si hacemos el post veremos que el modelo se ha "bindeado" de nuevo correctamente



NOTA
Hay otra forma de generar la vista de una manera más "elegante" y evitando así tener que usar un bucle y teniendo a nuestra alcance el Intellisense es la siguiente. Creamos una página parcial (Partial Page) llamada Item.cshtml  (mismo nombre que la clase que contiene la colección) en el directorio View/Home/RenderPartials o Shared/RenderPartials y en ella pondremos lo siguiente
@model test.web.mvc.cs.Models.Item

<div>
 @Html.HiddenFor(m => m.IdItem)
 @Html.HiddenFor(m => m.Description)
 @Model.Description
 @Html.TextBoxFor(m => m.Quantity)
</div>
Luego en la vista tan solo deberemos poner lo siguiente
@using (Html.BeginForm())
{ 
 @Html.EditorFor(x => x.Items)
 <input type="submit" value="Enviar" />
}

Happy coding!

martes, 24 de julio de 2012

Controles comunes en aplicaciones Metro

Desde hace un par de días estoy iniciándome en el desarrollo de aplicaciones Metro para Windows 8. Una vez instalado Windows 8 Release Preview y el Visual Studio 2012 RC tenemos todo lo necesario para comenzar con el desarrollo de este tipo de aplicaciones.

Una vez arrancado el Visual Studio seleccionaremos la plantilla Windows Metro Style en el lenguaje que más nos guste tal y como se muestra en la imagen


Tras esto se nos creará un proyecto de éste tipo con el siguiente aspecto


En este primer artículo voy a hablar un poco de los controles que tenemos a nuestra disposición para desarrollar para Metro ya que la lista puede agobiar un poco al principio, o al menos esa fue mi primera impresión ya que siempre he trabajado para aplicaciones web o como mucho alguna aplicación de escritorio de tipo WinForms y nunca he hecho nada serio para WPF o Silverlight.

Controles más comunes
  • Border: Dibuja un borde, un fondo o ambos alrededor de un objeto.
<Border BorderBrush="Black" BorderThickness="1" 
        Height="120" Width="60">
    <StackPanel>
        <Rectangle Fill="Red"/>
        <Rectangle Fill="Green"/>
    </StackPanel>
</Border>
  • Button: Representa un control de tipo botón que interpreta un click del usuario.
<Button .../>
-or-
<Button>
    singleObject
</Button>
-or-
<Button ...>stringContent</Button>
  • CheckBox: Representa un control que el usuario puede marcar (check) o desmarcar (uncheck). Este control también puede tener un valor indeterminado.
<CheckBox .../>
-or-
<CheckBox>
  singleObject
</CheckBox>
-or-
<CheckBox>stringContent</CheckBox>
  • ComboBox: Control de selección que combina un textbox no editable y un drop-down list que permite al usuario seleccionar un elemento de una lista.
<ComboBox x:Name="ComboColores" Height="20" Width="150" ItemsSource="{Binding}" />
ObservableCollection<string> colores = new ObservableCollection<string>();
colores.Add("Rojo");
colores.Add("Verde");
colores.Add("Azul");
     
ComboColores.DataContext = colores;
  • FlipView: Representa un control para mostrar elementos, pero que muestra un elemento cada vez, y tiene un comportamiento de "flip" cuando se pasa de uno a otro.
Control FlipView usado para mostrar una galería de imágenes
  • Grid: Define un área flexible organizada en filas y columnas. Los elementos hijos son organizados en base a la cantidad de filas y columnas definidas.
  • GridView: Muestra un Grid horizontal de elementos de datos.
Metro GridView
  • Image: Control que muestra una imagen. La imagen puede estar en varios formatos (Joint Photographic Experts Group [JPEG], Portable Network Graphics [PNG], Bitmap [BMP], Graphics Interchange Format [GIF], Tagged Image File Format [TIFF], JPEG XR, icons [ICO]).
  • ListView: Muestra una lista de elementos de manera vertical.
Metro ListView
  • RadioButton: Le permite al usuario seleccionar una opción de un grupo de opciones.
  • StackPanel: Organiza una lista de elementos hijo en una única fila que puede ser orientada de manera vertical u horizontal.
  • <StackPanel x:Name="MyStackPanel">
      <TextBlock x:Name="TextFirstName" Text="Nombre" Width="75" HorizontalAlignment="Left"/>
      <TextBlock x:Name="TextLastName" Text="Apellidos" Width="75" HorizontalAlignment="Left"/>
      <TextBlock x:Name="TextAddress" Text="Dirección" Width="150" HorizontalAlignment="Left"/>
    </StackPanel>
  • TextBlock: Control que nos ayuda a mostrar una pequeña cantidad de texto.
<TextBlock ...>text</TextBlock>
-or-
<TextBlock>
  oneOrMoreInlineElements
</TextBlock>
-or-
<TextBlock .../>
Otros controles que nos pueden ser útiles
  • AppBar: Representa un control contenedor que contiene los componentes de interfaz de usuario para ejecutar acciones.
Metro AppBar
  • Canvas: Define un área en la que pueden colocarse explícitamente objetos, usando coordenadas que son relativas al "Canvas".
<Canvas Width="640" Height="480" >
    <Rectangle Canvas.Left="30" Canvas.Top="30" 
       Fill="Red" Width="200" Height="200" />
</Canvas>
  • Frame: Representa un control de contenido que soporta la navegación.
  • MediaElement: Representa un objeto que contiene audio, vídeo o ambos.
<MediaElement Source="Media/video1.mp4" AutoPlay="True" />
  • SemanticZoom: Representa un control con scroll que contiene dos vistas que tienen una relación semántica.
<SemanticZoom ...>
  <SemanticZoom.ZoomedOutView>
    zoomedOutViewContent
  </SemanticZoom.ZoomedOutView>
  <SemanticZoom.ZoomedInView>
    zoomedInViewContent
  </SemanticZoom.ZoomedInView>
</SemanticZoom>
Metro SemanticZoom
Metro SemanticZoom
  • Slider: Representa un control que permite al usuario seleccionar un valor dentro de un rango.
Metro Slider
Con esto acabamos la introducción a los controles que tenemos a nuestra disposición en la aplicaciones Metro. En los próximos artículos iremos viendo como utilizarlos dentro de nuestras aplicaciones.


Happy coding!

miércoles, 4 de julio de 2012

Entity Framework y el borrado de entidades (II) - usando lambda y árboles de expresión

Como ya explique en el artículo anterior la forma más natural de borrar un registro es a través de su clave primaria, aunque eso no siempre tiene porque ser así. Un par de ejemplos sobre esto puede ser
  • Borrar aquellos registros que tengan más de un año de antigüedad. Práctico en tablas de logs.
  • Borrar aquellos registros que tengan un estado determinado.
  • O simplemente querer borrar registros en base a una clave ajena, como por ejemplo, borrar todas los lineas de una factura.
En todos estos casos la solución planteada en el artículo anterior no nos valdría ya que asumimos que tan sólo vamos a borrar un registro.

Borrado de varias entidades
Basándonos en este ejemplo
public class Bar
{
  public int IdBar { get; set; }
  public string Description { get; set; }
  public int IdState { get; set; }
}
y queriendo borrar aquellos registros que estén en el estado 1 podríamos hacer lo siguiente
using (DataContext context = new DataContext())
{
  var list = context.Bar.Where(m => m.IdState == 1);
  foreach (Bar bar in list)
    context.Bar.Remove(bar);
  context.SaveChanges();
}
Si analizamos el código anterior veremos que para borrar n elementos, debemos hacer n + 1 accesos a la base de datos. Lanzaremos n consultas de borrado, y necesitaremos una más para recuperar los elementos a borrar.

Como últimamente me he vuelto un inconformista esta solución no me gusta porque para borrar 1000 elementos necesito hacer 1001 acceso a base de datos y eso me parece demasiada carga para un servidor, que en mi caso, ya anda demasiado justo de recursos.

La primera solución que se me ocurrió fue usar un método de este estilo
using (DataContext context = new DataContext())
{
  context.Database.ExecuteSqlCommand("DELETE FROM Bar WHERE IdState = @IdState", new 
object[] { new System.Data.SqlClient.SqlParameter("IdState", 1) });
}
Esta solución es bastante buena aunque me deja atado a una tabla y a un filtro en concreto, lo cual me obliga a estar estableciendo métodos por cada tabla donde desee borrar un conjunto de datos y si uso varios filtros a estar usando parámetros opcionales (que suelen afear el código bastante).

Para mi lo ideal sería en un sólo método poder resolver esta situación, y tras investigar un poco se puede hacer con algo de código extra. Dado que estoy usando Code First he creado un método Delete en el contexto con el siguiente aspecto
public void Delete<T>(Expression<Func<T, bool>> condition)
{
  string where = generateWhere(condition.Body);
  string query = String.Format("DELETE FROM {0} WHERE {1}", typeof(T).Name, where);
  ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreCommand(query);
}
De esta manera puedo pasar que entidad estoy intentado borrar y los filtros que voy a usar en el borrado. Antes de continuar me gustaría aclarar que transformar un árbol de expresion a una condición SQL no es una tarea fácil y esta llena de pequeño matices que puede que hagan que no sea rentable realizar el esfuerzo. En mi caso las condiciones de borrado son muy simples y la mejora de rendimiento (que veremos al final) justificaban el pequeño esfuerzo que ha llevado el desarrollo de este método. Pero ojo, hacer un LINQ Provider no es una tarea que se pueda considerar trivial.

Bien, con esto podríamos llamar a nuestro método de borrado de la siguiente manera
using (DataContext context = new DataContext())
{
  context.Delete<Bar>(m => m.IdState == 1);
}
Si analizamos nuestra Expression de entrada vemos como tiene una propiedad Body donde está la/s condiciones que hemos pasado y que tenemos que transformar a una condición Where de SQL. En esta propiedad tenemos tanto la parte izquierda como la parte derecha de la condición, así como el operador que se está usando. En el método generateWhere analizaremos todas estas partes para devolver un Where válido.
private string generateWhere(dynamic operation)
{
  string left = generateToken(ExpressionTypeEnum.Left, operation.Left);
  string right = generateToken(ExpressionTypeEnum.Right, operation.Right);

  // TODO: Completar operaciones (por ahora con estas es suficiente)
  var ops = new Dictionary();
  ops.Add(ExpressionType.Equal, "=");
  ops.Add(ExpressionType.GreaterThan, ">");
  ops.Add(ExpressionType.GreaterThanOrEqual, ">=");
  ops.Add(ExpressionType.LessThan, "<");
  ops.Add(ExpressionType.LessThanOrEqual, "<=");

  ops.Add(ExpressionType.And, "AND");
  ops.Add(ExpressionType.AndAlso, "AND");
  ops.Add(ExpressionType.Or, "OR");
  ops.Add(ExpressionType.OrElse, "OR");

  return string.Format("{0} {1} {2}", left, ops[operation.NodeType], right);
}
En mi caso estoy tomando como base que la Expression es de tipo BinaryExpression aunque más exactamente es de tipo LogicalBinaryExpression (esto lo podemos comprobar en tiempo de ejecución). En otras expresiones este análisis de la expresión fallaría por no tener alomejor una propiedad Right.

Vemos que tanto para la parte izquierda como para la parte derecha llamamos al método generateToken que se encarga de generarnos una cadena con el valor contenido en esa parte, e incluso, de llamar recursivamente al método generateWhere en caso que estemos combinado filtros de esta manera
using (DataContext context = new DataContext())
{
  context.Delete<Bar>(m => m.IdState == 1 || m.IdState == 2);
}
El método generateToken tendría el siguiente aspecto
private string generateToken(ExpressionTypeEnum type, dynamic operation)
{
  string token = string.Empty;
  if (operation is BinaryExpression)
    token = generateWhere(operation);
  else
    token = (type == ExpressionTypeEnum.Left ? operation.Member.Name : operation.Value.ToString());
   
  return token;
}
Como único detalle hay que tener en cuenta que dependiendo de que parte de la expresión estemos analizando extraeremos el token de una u otra propiedad.

Con esto ya tenemos nuestro pequeño "parser" listo para ser usado en un entorno controlado y con condiciones simples. He detectados otras expresiones que poco a poco iré añadiendo. Estas expresiones son
  • UnaryExpression. Para filtros de tipo m => !m.IsActive. Donde IsActive es de tipo boolean.
  • PropertyExpression: Para filtros de tipo m=> m.IsActive. Donde IsActive es de tipo boolean.
  • MethodBinaryExpression: Para filtros de tipo m=>m.Date < DateTime.Now. Donde como es lógico Date es de tipo DateTime.
Para ver la mejora de rendimiento he realizado un borrado iterativo y un borrado con esté método usando el siguiente código
Iterativo
using (DataContext context = new DataContext())
{
  var list = context.Bar.Where(m => m.IdState == 1);
  foreach (Bar bar in list)
    context.Bar.Remove(bar);
  context.SaveChanges(); 
}
Directo
using (DataContext context = new DataContext())
{
  context.Delete<Bar>(m => m.IdState == 1);
}

He lanzado estos métodos borrado 10, 100, 1000 y 10000 elementos. Cada bloque lo he lanzado tres veces y he calculado la media para dar la duración de la duración. Con estas condiciones estos son los datos que he obtenido

Registros a borrar - Tiempo de ejecución en ms 

Conclusiones
Como vemos en la tabla para borrados de más de 1000 registros el borrado iterativo se puede vuelve un poco pesado, ya que nos lleva casi 4 segundos ejecutarlo (producto de tener que lanzar 1001 consultas a la base de datos), mientra que nuestro borrado directo no llega a los 12 ms. En condiciones más extremas (10.000 registros) el borrado iterativo llega a casi 2 minutos de ejecución mientras que el directo no nos pasa de un cuarto de segundo. Interesante, ¿verdad?

En la mayoría de los escenarios no merece la pena complicarnos la vida tanto ya que tan solo borraremos un par de registros y podemos optar por el método iterativo, ya que como vemos entre ambos métodos para 10 registros casi no tenemos diferencias de tiempos. Para borrados de más registros siempre podemos optar procedimientos almacenados o lanzar directamente nosotros la consultas desde nuestro programa, pero si queremos tener a nuestra disposición mucho filtros para borrar está opción nos puede valer.

Eso si, como ejercicio de programación ha estado realmente bien y me he permitido ver por encima como funcionan los árboles de expresión.
Happy coding!

martes, 3 de julio de 2012

Entity Framework y el borrado de entidades (I)

A la hora de borrar entidades en Entity Framework nos damos cuenta que podemos actuar de dos maneras diferentes sobre todo si tenemos en cuenta factores como el número de consultas que tenemos que lanzar contra nuestra base de datos.

Borrado de entidades por la clave primaria
Quizás es la forma más natural de realizar un borrado aunque no por ello es la única. Supongamos que tenemos la siguiente entidad POCO con la cual hemos montado nuestra base de datos a través de Code First.
public class Bar
{
  public int IdBar { get; set; }
  public string Description { get; set; }
  public int IdState { get; set; }
}
El código para borrar una entidad por su clave primera podría ser algo así
private void DeleteByID(int idBar)
{
  using (DataContext context = new DataContext()) {
    Bar bar = context.Bar.Where(m => m.IdBar == idBar).SingleOrDefault();
    context.Bar.Remove(bar);
    context.SaveChanges();
  }
}
¿Sencillo verdad? La verdad es que si, aunque si somos un poco curiosos o simplemente sabemos lo que estamos haciendo y usamos el SQL Server Profiler veremos que la ejecución de ese código tan simple genera estas dos consultas
exec sp_executesql N'SELECT TOP (2) 
[Extent1].[IdBar] AS [IdBar], 
[Extent1].[Description] AS [Description], 
[Extent1].[IdState] AS [IdState]
FROM [dbo].[Bar] AS [Extent1]
WHERE [Extent1].[IdBar] = @p__linq__0',N'@p__linq__0 int',@p__linq__0=1
exec sp_executesql N'delete [dbo].[Bar]
where ([IdBar] = @0)',N'@0 int',@0=1
O sea, que estamos lanzando dos consultas contra nuestra base de datos para simplemente hacer un borrado. Esto desde mi punto de vista es un poco absurdo, aunque menos mal que con un pequeño truco podemos resolver este pequeño inconveniente. El truco consiste en adjuntar a nuestro contexto una entidad con la clave que queramos borrar, luego la borramos y grabamos los cambios. Con esto se lanzará la consulta de borrado con la información de la clave que deseamos borrar. El código para esto es el siguiente
private void DeleteByID(int idBar)
{
  using (DataContext context = new DataContext())
  {
    Bar bar = new Bar() { IdBar = idBar };
    context.Bar.Attach(bar);
    context.Bar.Remove(bar);
    context.SaveChanges();
  }
}
Si usamos el SQL Profiler con este método veremos que tan solo se ejecuta esta consulta
exec sp_executesql N'delete [dbo].[Bar]
where ([IdBar] = @0)',N'@0 int',@0=1
Como vemos, con un pequeño cambio hemos podido resolver de una manera fácil el problema de rendimiento que podríamos tener si hacemos muchos borrados en nuestra aplicación.

En el próximo artículo trataré el borrado de registros cuando no estamos borrando por la clave primaria y donde una vez más el número de accesos a la base de datos puede ser un factor muy importante a tener en cuenta.

Happy codding!

viernes, 29 de junio de 2012

Cuidado con los redondeos porque puedes perder algún céntimo

Hoy voy a hablar sobre uno de esos fallos que te puede volver loco toda una mañana e incluso hacerte perder los papeles, sobre todo al final cuando te das cuenta del fallo.

En esta ocasión la cosa va de redondeos de importes de facturas así que lo primero que haremos es buscar como se redondea los valores en euors. Según la sección 3, artículo 11 de la ley 46/1998, de 17 de diciembre (consultar aquí), sobre la introducción del euro

Uno. En los importes monetarios que se hayan de abonar o contabilizar, cuando se lleve a cabo una operación de redondeo después de una conversión a la unidad euro, deberán redondearse por exceso o por defecto al céntimo más próximo. Los importes monetarios que se hayan de abonar o contabilizar y se conviertan a la unidad monetaria peseta deberán redondearse por exceso o por defecto a la peseta más próxima. En caso de que al aplicar el tipo de conversión se obtenga una cantidad cuya última cifra sea exactamente la mitad de un céntimo o de una peseta, el redondeo se efectuará a la cifra superior.

O sea que debemos redondear a dos decimales al céntimo más próximo y en caso que el tercer decimal sea 5 debemos redondear al alza. En base a esto haremos unas pruebas para ver el resultado
decimal d1;
decimal d2;

d1 = 123.472m;
d2 = Math.Round(d1, 2);
Print(d1, d2);

d1 = 123.478m;
d2 = Math.Round(d1, 2);
Print(d1, d2);

d1 = 123.475m;
d2 = Math.Round(d1, 2);
Print(d1, d2);
La salida de este programa es la siguiente
Valor: 123,472
Valor redondeado: 123,47
---
Valor: 123,478
Valor redondeado: 123,48
---
Valor: 123,475
Valor redondeado: 123,48
Como vemos todo funciona correctamente pero vamos a usar el valor 123,465 que según la ley debería ser redondeado a 123,47.
d1 = 123.465m;
d2 = Math.Round(d1, 2);
Print(d1, d2);
Y la salida sería
Valor: 123,465
Valor redondeado: 123,46
Si nos fijamos, vemos que el valor obtenido no es el que esperamos, y con este error nos tropezamos el otro día. Estabamos convencidos que el código estaba bien, ya que la función Math.Round hace el redondeando al alza en caso de ser un cinco. Tras mucho darle vueltas al asunto y algun que otro "me cago en todo", nos dio por leernos con detalle la ayuda del método Round.

El valor devuelto por el método Math.Round es "el número más próximo a d con una precisión igual a decimals. Si d se encuentra entre dos números, uno de los cuales es par y el otro es impar, se devuelve el número par. Si la precisión de d es menor que decimals, se devuelve d sin modificar."

Vaya, ¿y esto?, para mi que el método Math.Round no hacía esto, pero por lo que parece esto lo ha hecho de siempre así que la memoria nos ha gastado una mala pasada. Para que el redondeo sea el esperado debemos usar otra sobrecarga de dicho método, en la que podemos indicar que tipo de redondeo queremos usar, quedando nuestro código así
d1 = 123.465m;
d2 = Math.Round(d1, 2, MidpointRounding.AwayFromZero);
Print(d1, d2);
Obteniendo la siguiente salida
Valor: 123,465
Valor redondeado: 123,47
Así que, cuidado con los redondeos no sea que nos llevemos un susto en la facturación a final de año.

Happy coding!

miércoles, 20 de junio de 2012

Validar el formato de una imagen (no me mientas con el formato) con C#

De verdad que hay veces en la que es mejor estarse callados porque si hablas puedes abrir La caja de Pandora y al final terminarás muy pero que muy mal.

Toda esta historia comienza con un simple FileUpload que permite al usuario subir una imagen. En principio esto no debería dar ningún problema, es algo que se encuentra perfectamente documento en Internet y en menos de 2 minutos lo tienes montado en tu aplicación. El problema surge cuando a alguien se le ocurre hacer la siguiente pregunta, ¿qué pasa si no suben una imagen, o sea, si algún avispado coge un ejecutable y le cambia la extensión a por ejemplo, jpg? La verdad es que mis conocimientos sobre seguridad no llegan a tanto y no se cuales serías las implicaciones reales sobre tal acción pero con semejante pregunta ya tenemos el lío montado así que, toca hacer un sistema para comprobar que la imagen que el usuario ha subido es realmente la imagen que dice ser.

Lo primero es preguntarnos cuales son los formatos gráficos que vamos a admitir, lo cual, es una mala pregunta porque la respuesta fue, todos. Eso es imposible así que, vamos a limitarlo a 3 o 4, así que la cosa quedó en los más utilizados, esto es, jpeg, gif, png y bmp.

Para esto podríamos hacer uso del objeto Image que nos da .NET, pero alguien (y no soy yo) se le metieron en la cabeza estás dos cosas
  • Usar el objeto Image es poco eficiente.
  • Referenciar a System.Drawing en la capa de negocio es poco elegante.
De todas formas aquí está como podría ser este código (por si alguien quiere usarlo)
public bool validateImage(byte[] bytes)
{
  try 
  {
    Stream stream = new MemoryStream(bytes);
    using(Image img = Image.FromStream(stream))
    {
      if (img.RawFormat.Equals(ImageFormat.Bmp) ||
          img.RawFormat.Equals(ImageFormat.Gif) ||
          img.RawFormat.Equals(ImageFormat.Jpeg) ||
          img.RawFormat.Equals(ImageFormat.Png))
        return true;
    }
    return false;
  } 
  catch
  {
    return false;
  }
}
Tras revisar un poco de documentación sobre estos formatos (la wikipedia es un lugar fantástico) llegamos a esta conclusión.
  • JPEG: Los primeros 4 bytes son FF D8 FF E0 (aunque parece que lo realmente seguro son los dos primeros bytes, ya que por ejemplo algunas cámaras Canon ponen FF E1 en el tercer y cuatro byte).
  • GIF: Los primeros 6 bytes son siempre "GIF87a" o "GIF89a".
  • PNG: Los primeros 8 bytes son 89 50 4E 47 0D 0A 1A 0A.
  • BMP: Los primeros 2 bytes son 42 4D.
Con esta información ya nos podemos poner manos a la obra. Para realizar las validaciones implementamos una pequeña factoría de validadores de imágenes ya que después de esto vinieron más cosas, y al final lo mejor fue encapsular todo el comportamiento específico de cada imagen en un clase (como se debería hacer siempre, ¿no?).
Nuestra interface para la validación del formato
public interface IImageValidator
{
  byte[] Content { get; set; }
  bool IsValid();
}
Nuestra factoría de interfaces
public static IImageValidator Create(string extension, byte[] content)
{
  switch (extension.ToUpper())
  {
    case "BMP":
      return new BMPImageValidator() { Content = content };
    case "GIF":
      return new GIFImageValidator() { Content = content };
    case "JPG":
    case "JPEG":
      return new JPEGImageValidator() { Content = content };
    case "PNG":
      return new PNGImageValidator() { Content = content };
    default:
      throw new Exception(string.Format("Format '{0}' not supported", extension));
  }
}
Y por último como sería el validador para el caso de un fichero jpg
public class JPEGImageValidator : IImageValidator
{
  #region IImageValidator

  public byte[] Content { get; set; }

  public bool IsValid()
  {
    byte[] magicNumber = { 0xFF, 0xD8 };   
    return (Content.Take(2).ToArray() == magicNumber);
  }

  #endregion
}
Para usar el validador tan solo debemos hacer lo siguiente
byte[] imageJPG = System.IO.File.ReadAllBytes("test-jpg.jpg");
IImageValidator validator = ImageValidatorFactory.Create("jpg", imageJPG);
bool isValid = validator.IsValid();
Para la prueba estoy cargando la imagen desde un fichero. Si queremos usarlo en un entorno web (MVC) podemos hacer lo siguiente
string extension = string.Empty;
if (file.FileName.LastIndexOf('.') > 0)
  extension = file.FileName.Substring(file.FileName.LastIndexOf('.') + 1);       
MemoryStream memoryStream = new MemoryStream();
file.InputStream.CopyTo(memoryStream);
byte[] content = memoryStream.ToArray();

IImageValidator validator = ImageValidatorFactory.Create(extension, content);
bool isValid = validator.IsValid();
Respecto a la eficiencia de los métodos, he modificado el método validateImage para que en vez de validar un byte[] también valide un Stream, para ahorrarnos esta conversión y así ser más justos en la comparación. Los resultados son realmente demoledores

  • validateImage (byte[]): 5601 ms.
  • validateImage (stream): 5157 ms.
  • ImageValidatorFactory: 4 ms.

Así que realmente el uso de la clase Image es un factor a tener en cuenta en caso que trabajemos de manera masiva con imágenes.

Viendo estos números puede que quede justificado hacer nuestros propios validadores de imágenes aunque para otras tareas puede que no quede tan justificado sobre todo teniendo en cuenta los mil y un detalles que hay que tener en cuenta cuando trabajamos con este tipo de ficheros a bajo nivel.

Happy coding!