Archivo de la etiqueta: javascript

Artículo Invitado: ECMAScript 6 y la nueva era de JavaScript por @CKGrafico

Comenzamos con este artículo una nueva sección llamada “Artículos Invitados”, en este caso tengo la suerte de contar con Quique Fernandez Guerra, Microsoft Student Partner y desarrollador Javascript:

Quique Fdez GuerraQuique Fdez. Guerra
Desarrollador y amante de JavaScript
Twitter: @CKGrafico
Web: CKGrafico.com

Quique es un usuario muy activo de comunidades de desarrollo frontend, y le hemos visto en varios hangouts mostrando su experiencia, así que le he pedido que nos cuente sus impresiones de lo que está por venir en la nueva versión del estandar ECMAScript 6, en el cual se basarán las próximas versiones de Javascript. A continuación sus impresiones


Desde siempre se ha considerado a JavaScript cómo un lenguaje simplón, es seguramente uno de los lenguajes actuales más sencillos de aprender, pero además es conocido por no ser muy completo (ya sea por la manera de trabajar con las clases, o los artículos sobre ‘JavaScript the weird parts’).

Por otro lado, en los últimos años JavaScript a empezado a tener más importancia hasta el punto que se ha vuelto el único lenguaje universal, es decir, lo encontramos en web, servidor, hardware, móvil, etc, cómo ya comenté en un artículo hace un tiempo.

Aún así el lenguaje sigue igual, de hecho ha llegado un momento en que la gente sabe mucho más sobre frameworks del lenguaje que del propio lenguaje. Está lleno de ofertas de trabajo en las que se pide conocimientos en jQuery y Backbone o Angular y por supuesto hay mucha gente aprendiendo directamente estos frameworks (Aprender un framework antes de saber el propio lenguaje…).

Por suerte, parece que con la nueva versión del estándar ECMAScript vamos a poder tomar más en serio JavaScript, aunque cómo siempre vamos a tener que esperar que todos los navegadores lo soporten. A continuación voy a explicar las partes que considero más importantes de esta nueva versión.

Declaración let

Ahora podemos declarar variables que existan solo en un bloque de código, entendiendo por bloque de código desde una función hasta un bucle o una condición.

if(1) {
var a = 5;
let b = 6;
console.log(a,b); // 5 6
}

console.log(a,b); // b is not defined

Constantes, ¡¡Sí constantes!!

Ya era hora de poder utilizar constantes en nuestro apreciado JavaScript, muy sencillas de utilizar igual que en otros lenguajes.

const PI = 3.14;
console.log(PI); // 3.14

function test() {
 console.log('test', PI); // test 3.14
}

test();

PI = 6; // Error!!

Arrow functions

Si trabajas con lenguajes cómo C# que tienen lambda verás que es algo parecido, que se ha traído a JavaScript.

let simple = a => a / 2;
console.log(simple(8)); // 4

let complex = (a, b) => {
 if (a < b) {
 return a;
 }
 return b;
}

console.log(complex(3,6)); // 3

Valores por defecto en parámetros

Otro ejemplo más de algo que tienen casi todos los lenguajes y JavaScript aún no lo tenía, pero ya está aquí.

function test(a, b = 10) {
 return a + b;
}

console.log(test(1)); // 11
console.log(test(1,2)); // 3

Rest parameters

Nos va a ser muy útil cuando no sepamos el número de parámetros exactos, muchas veces usábamos arguments para eso, pero ahora vamos a tenerlo mucho más fácil.

function test(a, b = 1, ...c) {
 return a + b + c.length || 0;
}

console.log(test(1)); // 2
console.log(test(1,10,1,1,1,1)); // 15

Pero no solo eso, también lo vamos a poder utilizar en un array o al llamar a una función.

let arr = [4, 5, 6];
let numbers = [1, 2, 3, ...arr, 7, 8];

console.log(numbers); // [1, 2, 3, 4, 5, 6, 7, 8]

Object literals

Simplificaremos los objetos, de manera que no haya que poner información irrelevante.

// ECMA 5
var world = 'world';
var obj = {
 world: world,
 hello: function() {
 console.log('hello', this.world);
 }
};

obj.hello(); // hello world

// ECMA 6
let world6 = 'world';
let obj6 = {
 world6,
 hello() {
 console.log('hello6', this.world6);
 }
};

obj6.hello(); // hello6 world

for..of

La evolución lógica del for..in

// ECMA 5
var arr = ['a', 'b', 'c'];
for(var i in arr) {
 console.log(arr[i]); // a, b, c
}

// ECMA 6
let arr6 = ['a', 'b', 'c'];
for(let i of arr6) {
 console.log(i); // a, b, c
}

Generadores

Un nuevo tipo de función que nos ayuda a crear un iterador de manera fácil, utilizan yield en vez de return que es una nueva palabra reservada.

function* range(start, end) {
 for (let i = start; i <= end; i++) {
 yield i;
 }
}

var ranger = range(1,10);

var res = {
 value: null,
 done: false
};

while(!res.done){
 res = ranger.next();
 console.log(res.value, res.done);
}

Symbol

symbol es un nuevo tipo de dato y Symbol() nos devuelve un objeto único de tipo symbol, pensado para tener objetos o métodos que son distintos de los demás, sería un sustituto a usar cadenas para los nombres de los métodos por ejemplo.

let myMethod = Symbol();
let obj = {
 [myMethod]() {
 console.log('Soy único e irrepetible');
 }
};

obj[myMethod](); // Soy único e irrepetible
console.log(typeof myMethod); // symbol

Map

El objeto Map  es un objeto de clave / valor, la mejor manera de entenderlo es ver un ejemplo.

let map = new Map();
let arr = [];
map.set('string', 'Ola k ase');
map.set(arr, [1, 2, 3, 4]);
map.set(typeof 8, 'I\'m a number');

console.log(map.size); // 4

console.log(map.get('string')); // Ola k ase
console.log(map.get(typeof 1)); // I'm a number
console.log(map.get([])); // undefined -> arr !== []
console.log(map.get(arr)); // [1, 2, 3, 4]

Set

Sirve para poder crear algo parecido a las listas en otros lenguajes, aunque aún bastante simple.

let set = new Set();
set.add('test');
set.add(8);
set.add('Quique');

console.log(set.size); // 3
console.log(set.has(8)); // true

set.delete('Quique');

set.forEach(function(value) {
 console.log(value); // test 8
});

Clases

Vamos a tener clases en condiciones, más o menos van a hacer lo mismo que hasta ahora pero vamos a tener una sintaxis más sencilla para implementarlas.

class Human {
 constructor(name = 'anonymous') {
 this.name = name;
 }

 hello() {
 console.log('Welcome to the world ' + this.name);
 }
}

class Male extends Human {
 constructor(name) {
 super(name);
 this.sex = 'male';
 }

 get age() {
 return this._age;
 }

 set age(age) {
 this._age = age;
 }
}

let me = new Male('Quique');
me.hello();
me.age = 1;
console.log(me.age); // 1

Módulos

Ha llegado la hora de poder crear partes de nuestro código por separado e importarlas cuando nos sea conveniente, para no cargarlo todo de golpe y trabajar de una manera ordenada.

// number.js
module 'number' {
 let num = 8;
 export class Number {
     constructor() {
         console.log('The number is: ' + num);
     }
 }

}

// app.js
module number from '/number.js';
import Number from 'number';

var n = new Number(); // The number is 8

Templates

Una de las cosas que más he usado este último año en JavaScript han sido los templates, sobretodo trabajando Handlebars, pues ahora mismo se convierten en algo propio de este lenguaje.

let name = 'Quique', twitter = 'CKGrafico';
let template = `Hello, this is ${name}, find my on ${twitter}`;
// Nota, fíjate en las ` que no es lo mismo que '
console.log(template); // Hello, this is Quique, find my on CKGrafico

Estas son las cosas más destacables que trae la nueva versión, puedes encontrar la lista entera en su especificación.

Mientras esperas a que sea compatible en los navegadores puedes trabajar con ECMA6 en ES6 fiddle (un sandbox) o utilizar un pequeño transpiler llamado Traceur que te permite trabajar en ECMA6 y compilar a ECMA5

 


Si tienes preguntas o comentarios no dudes en dejarlas en la sección de comentarios, y si tienes más información sobre Quique, aquí tienes algunos datos de contacto:

Quique Fdez GuerraQuique Fdez. Guerra
Desarrollador y amante de JavaScript
Twitter: @CKGrafico
Web: CKGrafico.com

Anuncios

Cacheando con Varnish un proyecto ASP.net MVC5

Una caché, por definición, es un almacenamiento a corto plazo de información y con una altísima velocidad de acceso, permitiéndonos mejorar el rendimiento de nuestros sistemas. En el caso de la web podemos diferenciar dos tipos:

  • Caché de cliente, que se hace en el navegador y que nos permite no tener que traer de internet imágenes o ficheros de estilo una vez hemos obtenido una copia.
  • Caché de servidor, que guarda una copia de manera temporal para evitar sobrecarga de nuestro servidor de aplicaciones.

Esto último tiene una justificación, y es que el acceso a las aplicaciones (PHP, ASP.net, Ruby) es un proceso relativamente lento que suele estar acompañado de un acceso a una base de datos, una aplicación de la lógica de negocio y la composición final de la página.

Existen diferentes sistemas y tipos de caché, como Memcached o Redis. En este artículo hablaremos de Varnish, un proyecto open-source que se instala sobre sistemas UNIX (aunque tiene soporte para Windows mediante Cygwin).

La principal peculiaridad que tiene este sistema, además de sus casi-infinitas opciones de configuración, es que permite dividir nuestra página en trozos y cachearlos de manera independiente, en función del intervalo de actualización de los mismos, un proceso conocido como Edge Side Includes (ESI) y que veremos a lo largo del artículo.

Instalación y configuración

La instalación de Varnish es un proceso tan simple como brew install varnish si usamos homebrew en mac. Una vez instalado, para ejecutarlo usamos el siguiente comando:

sudo /usr/local/opt/varnish/sbin/varnishd -n /usr/local/var/varnish -f /usr/local/etc/varnish/default.vcl -s malloc,1G -T 127.0.0.1:2000 -a 0.0.0.0:8082

pasando como parámetros las siguientes opciones:

  • Ruta del fichero de configuración
  • Puerto de registro de log
  • Máximo consumo de RAM
  • Puerto de escucha (en nuestro caso el 8082)

El fichero de configuración default.vcl, para nuestro ejemplo, contiene las siguientes directivas:

backend default {
    .host = "127.0.0.1";
    .port = "8087";
}

sub vcl_recv {
	if (req.http.cookie) {
		unset req.http.cookie;
	}
}

sub vcl_fetch {
	
	if (req.url == "/layout/*") {
       set beresp.ttl = 2m;      /* Sets a one minute TTL on        */
    } else {
       set beresp.do_esi = true; /* Do ESI processing               */
       set beresp.ttl = 30s;     /* Sets the TTL on the HTML above  */
    }
    unset beresp.http.set-cookie;
}

sub vcl_deliver {

    if (obj.hits > 0) {
            set resp.http.X-Cache = "HIT";
    } else {
            set resp.http.X-Cache = "MISS";
    }
}

Los comandos que hemos implementado son:

  • backend: Permite especificar qué servidores estarán funcionando al otro lado, se puede especificar una IP o un nombre DNS.

  • vcl_recv: En el caso de ASP.net, se genera una cookie de sesión al acceder al sitio, lo cual no siempre es lo deseable. En este ejemplo se borran todas las que provienen del servidor, de manera que se pueda cachear la página.

  • vcl_fetch: Se ejecuta cuando obtenemos un elemento desde el servidor, y en este caso especificamos que si estamos solicitando algún elemento de “layout” como el menú o la cabecera, ha de cachearlo durante 2 minutos, en caso contrario configuramos para que haga el procesamiento ESI (es decir, que intente unir los pedazos) y cachee el conjunto durante 30 segundos.

  • vcl_deliver: Nos permite editar la cabecera HTTP para saber si ha podido resolver el elemento en la caché o si ha tenido que acceder al servidor de aplicaciones.

Cacheando voy, cacheando vengo:

En este ejemplo hemos usado una plantilla de bootstrap que tiene el siguiente aspecto dentro de una aplicación prácticamente vacía en MVC5:

goal

Lo primero que podemos apreciar son tres zonas claramente diferenciadas, una cabecera, una barra lateral, y, finalmente, un área de contenido principal.

Estructura

Para mostrar la página, empleamos un controlador muy sencillo que genera una espera de 3 segundos para simular carga del servidor y almacena la fecha de generación en el ViewData:

public class HomeController : Controller
{
	public ActionResult Index ()
	{
		ViewData ["now"] = String.Format ("{0:HH:mm:ss}", DateTime.Now);
		System.Threading.Thread.Sleep (3000);
		return View ("Index");
	}
}

De manera adicional y para poder aplicar ESI, necesitaremos dividir nuestra vista en tres vistas diferentes que correspondan a acciones diferentes del controlador, que serán:

  • / <- que genera el contenido de la página
  • /layout/header <- que genera la cabecera
  • /layout/sidebar <- que genera la barra lateral

Las dos acciones del controlador Layout son idénticas, como muestra el código:

public class LayoutController : Controller
{
    public ActionResult Sidebar()
    {
		ViewData ["now"] = String.Format ("{0:HH:mm:ss}", DateTime.Now);
		System.Threading.Thread.Sleep (3000);
        return View ("Sidebar");
    }

	public ActionResult Header()
	{
		ViewData ["now"] = String.Format ("{0:HH:mm:ss}", DateTime.Now);
		System.Threading.Thread.Sleep (3000);
		return View ("Header");
	}
}

Nótese que por cada acción hemos agregado otros 3 segundos de retraso, teniendo un total de 9 segundos en el caso peor.

Para poder activar el ESI en las vistas, usamos etiquetas HTML que tienen el siguiente formato:

<esi:include src="/layout/sidebar" onerror="continue"/>

Además, a modo de prueba, podemos agregar algo de código javascript que se ejecute una vez cargada la página para apreciar la diferencia entre hora de generación y hora de renderización. Si todo ha ido bien, cuando carguemos por primera vez nuestra caché, se encontrará vacía, y sufriremos la espera de los 9 segundos.

En la imagen, G muestra la hora de generación en el servidor y R la hora de renderización en el cliente:

miss

Si volvemos a acceder, comprobaremos que el contenido de la página ya se ha cacheado, que las fechas de generación y de ejecución distan más de tres segundos, y que el inspector nos muestra el tiempo total de acceso a la página (700 milisegundos aprox):

hit

Conclusiones

Ha sido una prueba de concepto muy interesante, el hecho de descubrir que podemos tener nuestra web dividida en secciones con cachés diferentes nos da mucha movilidad al hacer portales con información dinámica. Varnish es una herramienta suficientemente compleja para ser tomada en serio y requiere que estudiemos a fondo sus características antes aplicarla a un sistema en producción.

Lecturas adicionales y enlaces

Del escritorio a la web: Mi charla en Madrid JS

Actualizacion: Vídeo de la charla ya disponible:

El pasado 10 de abril tuve mi primera experiencia como ponente en el grupo de MadridJS en la sala CAMON de Moncloa, Madrid, donde estuvimos hablando de nuestra evolución desde el escritorio a la web desarrollando el Web Workspace. Este artículo contiene un comentario de los ejemplos usados y las slides empleadas.

Bk4F638IMAEWxPq

Sigue leyendo

My february pet project: RealPoll (10+ technologies + a lot of fun)

Test it live: Realpoll at Azure

After my fist side-project (which I might publish on march or april) with Angular.js, I’ve been playing with different web technologies by doing a remake of a hackathon idea: Meet realpoll.

welcomeToRealPoll

The Idea

Teachers and speakers often need a way to engage the audience and give them the possibility to participate in the talk or the subject. Today is very common to see students tweeting from class, so this means they do have portable, wireless internet. The response of some centers is to block communications, but, why not use it the other way?

This web app allows the teachers to previously prepare some questions, choose the number of answers, the correct ones, and display the question on a projector. The students can then, use the url or capture the QR code generated from their cell phones. Once the question is generated, the trainer can choose the time that will be the poll open (in seconds).

When the time is up, the dashboard will mark the correct answers and those who answered correctly. The only data that is saved is the question and the answers, so you can come back and repeat it.

The voting interface is very, very simple: Just add a name and click on your chosen answer. It will be send inmediately to the dashboard.

Remake of a classic

The fact is that realpoll is a previous project done in a hackathon using a completely different tooling:

  • 100% HTML + Javascript
  • redis for the data layer
  • socket.io for handling the real time interaction
  • express.js for handling routing and views
  • google charts for the graphics
  • plain jquery for DOM management
  • Heroku as cloud host
  • developed with VIM

For this project, I wanted to keep the idea, but change completely the technologies used:

  • 50% HTML + Javascript, 50% C#
  • sql + entity framework for the data layer
  • signalr for the real-time interaction
  • ASP.net MVC for handling routing and views
  • Chart.js for the graphics
  • jquery and Angular.js for handling the views
  • RazorEngine for the views
  • Git/github as SCM
  • Windows Azure as cloud host (connected to github)
  • Visual Studio + IE dev tools + Chrome dev tools (+ Safari dev tools on mac)
  • Sendgrid for mailing.

Items

Architecture

The backend is pure ASP.net MVC with the data stored in a SQL Server database, and some services (such as email) for making my life a little bit easier.

The system uses the database for storing the questions, so we can access later from a single URL. The URL is a hash based on the question ID. The voting process is not stored, so it resets when we refresh the dashboard. The communication between the database and the app is done by using Entity Framework, Microsoft’s open source ORM.

For being able to use data without having to worry about the ORM, I used dependency injection techniques to inject a fake data source. The Depencency Injection framework chosen was ninject, and while I had to create two different classes for ASP.net MVC and SignalR dependency solvers, I had a single entry point to replace the fake access with the ORM data source.

Flow

Architecture

New question

The “New” page looks like this, It’s bootstrap for the UI and angular for handling the UI updates when the question number changes:

CreateQuestion

Created

When we create a question, data is updated in the database and we see a confirmation page like this:

Created

For generating the e-mail sent I use RazorParser, a nuget-available dll that allows me to generate an html view from a model and a file, and once generated use it as a string. The e-mail is sent through sendgrid’s SMTP, using the standard SMTP functions.

Result/dashboard Page

The result page is one of the most complicated, the charts are created by using chart.js with a wrapper for angular, the qr code is generated by using the qrickit API, and it’s updated in real time by using signalR and angular.js for handling the views.

Dashboard

When the time is up, the correct solution is highlighted, and those whose answer matches are highlighted also

Mobile Interface

Mobile

As Bootstrap is mobile ready, I had to do few changes to make the ui work flawlessly, had to do some debugging on Safari for Mac (whose web developer tools are way less powerul than Chrome/IE’s) connected to an iPhone. The cookie consent also adapts so, no issues here.

Stats and cookies

As the goal of the project was to play with technology, I havne’t been playing troo much with stats, but I did have added a google analytics code in each page. Also as I’m on the EU, there is a strict control of which cookies can be installed in the user’s machine (even more strict in Spain) so I’ve used the cookie consent code that allows the user to control the analytics tracking.

Source control, deploy and debug.

The project has been done by using git as source control manager, github as repository and the deployment has been done in Windows Azure. Azure has a hook for git, so when I push to github it will deploy to azure. As is git-based, it allows me to rollback inmediately while keeping the continuous deployment options available.

Finally, for remote debugging I added Elmah (Error Logging Modules and Handlers) to track down exceptions and issues that happened in Azure.

Issues, curious and weird things

  • There is a bug with angular an Visual Studio’s browser link that causes constant debugger stops on frontend code, be aware.
  • For adding dependency injection with ninject for signalR and MVC, you need to define two different dependency solvers, because they belong to different assemblies and implement different interfaces.
  • Validating input data has become way easier with HTML5, butS afari (and specially safari for iPhone) do not support the required tag for html, a useful guide is caniuse
  • For debugging on Safari for iPhone you need Safari running on Mac OS X.
  • When you re-deploy a solution to azure, (with the configuration by default) you lose all the exceptions tracked by elmah
  • I’ve used some funny xml transformations for handling local, remote and fake databases.

Room for improvement

Of course, there are always things that may go better, I didn’t write a single line of test code (other than my fake db wrapper) so it should be considered fairly unstable. The goal of this mini-project was to integrate as many technologies as possible to create a ready-to-deploy real-time web application. I would have added some UI tests with selenium, and maybe some unit testing for both angular and mvc controller.

Try it!

You can test it live on Realpoll at Azure or you can get the source code from the project’s github repository and deploy it by yourself. You will need your own API keys and your own database for making it work. Comments will also be apreciated, and if you want to contribute back, just send a pull request!

SignalR with external assemblies and obfuscators

Developing with SignalR is a very interesting experience. The technology, which allows us to create solutions that interact in real time with the browser and native apps, provides us with several layers of abstraction over technologies such as WebSockets, so that we can focus on the specific features of our apps. However, sometimes these abstractions may be a problem more than a solution.

One of the cases we can see this is with the hubs. A hub is a class that, when processed by signalR, is exposed to the browser by using Javascript. Unlike a REST API, a hub does not (only) responds to a request, they can also send messages both to the client who has made the request, the rest of the clients connected, or all of them, in real time.

To define a hub, we only need a class that inherits from the Hub class and SignalR will do the rest. It will discover (by using reflection) all the different hubs in the current assembly and generate the corresponding javascript.

Here is an example with the following code in C#:

public class ChatHub : Hub
    {
        public void Send(string name, string message)
        {
            // Call the broadcastMessage method to update clients.
            Clients.All.broadcastMessage(name, message);
        }
    }

The generated code by SignalR looks a little bit like this:

 proxies.chatHub = this.createHubProxy('chatHub');
        proxies.chatHub.client = { };
        proxies.chatHub.server = {
            send: function (name, message) {
                return proxies.chatHub.invoke.apply(proxies.chatHub, $.merge(["Send"], $.makeArray(arguments)));
             }
        };

As I mentioned earlier, signalR hubs are discovered automatically for the current assembly. What hapens if we store our hubs on a different asembly, for example, if we have two apps who use the same hub? After searching, I found the solution on StackOverflow. As I only needed to load one specific assembly, I picked only this line:

AppDomain.CurrentDomain.Load(typeof(Namespace.ChatHub).Assembly.FullName);

This code loads the Assembly that contains the class so SignalR can “discover” the Hub, we must place it just before the app.MapSignalR() or otherwise the Hub will not be generated.

Obfuscation

If we distribute our application our clients (for example when offering a solution containing SignalR so that they can install it on a local server) is usual to use tools like SmartAssembly or Dotfuscator, to protect the intellectual property of your code.

For a correct SignalR operation, it’s important to remember that we must not obfuscate, or prune the Hub classes, since the class is loaded by reflection. The obfuscation result will rename the classes and probably remove uncalled code (that is, in fact, called from Javascript). The best solution is to use hubs as a ‘proxy’ class and obfuscate those classes and methods called from the hub.

To avoid obfuscation you can can, either manually in the properties of the project, or through attributes. For SmartAssembly we find attributes such as [DoNotObfuscateType] and [DoNotPruneType] which apply to the whole class, and in the case of Dotfuscator we can use the [Obsufcation] attribute.

More information

Un tip rápido: SignalR, ensamblados externos y ofuscación

Desarrollar con SignalR es una experiencia muy interesante. La tecnología, que nos permite crear soluciones que interactúen en tiempo real con el navegador y con aplicaciones nativas, nos proporciona varias capas de abstracción sobre tecnologías como WebSockets, para que podamos centrarnos en el contenido de nuestras aplicaciones. Sin embargo, a veces los árboles no dejan ver el bosque.

Uno de los ejemplos se nos da con los hubs. Un hub es una clase que signalR expone al navegador mediante Javascript. A diferencia de una API REST, un hub no (solamente) responde a una petición, sino que puede enviar mensajes tanto al cliente que la ha realizado, a todos los clientes o al resto, en tiempo real, entre otras cosas.

Para definir un hub, solamente necesitamos una clase que herede de la clase Hub y SignalR hará el resto, es decir, descubrir los diferentes hubs y exponerlos al cliente.

Veamos un ejemplo, con el siguiente código en C#:

public class ChatHub : Hub
    {
        public void Send(string name, string message)
        {
            // Call the broadcastMessage method to update clients.
            Clients.All.broadcastMessage(name, message);
        }
    }

SignalR genera este código, que lo podemos ver acudiendo a la url http://miservicio/signalr/hubs:

 proxies.chatHub = this.createHubProxy('chatHub'); 
        proxies.chatHub.client = { };
        proxies.chatHub.server = {
            send: function (name, message) {
                return proxies.chatHub.invoke.apply(proxies.chatHub, $.merge(["Send"], $.makeArray(arguments)));
             }
        };

El hecho de que SignalR descubra de manera automática los hubs nos puede traer problemas cuando los hubs están en un ensamblado diferente al que está cargando SignalR (por ejemplo, si tenemos dos aplicaciones que usen exactamente el mismo tipo de hub).

Tras mucho buscar, la única solución que he encontrado para cargar los hubs desde otro ensamblado pasa por la siguiente línea:

AppDomain.CurrentDomain.Load(typeof(Namespace.ChatHub).Assembly.FullName);

Este código carga el ensamblado que contiene la clase para que SignalR “descubra” el Hub, y lo debemos situar justo antes de app.MapSignalR() o de lo contrario el Hub no se generará.

Ofuscación

Si distribuimos nuestra aplicación a nuestros clientes (por ejemplo ofrecemos una solución que contiene SignalR para que la puedan instalar en un servidor local) es habitual recurrir a herramientas como SmartAssembly o Dotfuscator, para proteger la propiedad intelectual de nuestro código.

Para que el funcionamiento de SignalR sea correcto, es importante recordar que no debemos ofuscar las clases Hub, ya que la clase se carga mediante reflexión, y la ofuscación provoca o bien que la clase no sea encontrada con su nombre original, o bien que no se pueda acceder a los métodos, o bien que, al no ser llamados por otras partes de nuestro código, se deseche. La mejor solución pasa por usar los hubs como una clase “pantalla” y ofuscar aquellas que sean llamadas desde el hub.

Para evitar la ofuscación podemos, o bien de manera manual en las propiedades del proyecto, o a través de atributos. En el caso de SmartAssembly encontramos atributos como [DoNotObfuscateType] y [DoNotPruneType] que se aplican a toda la clase, y en el caso de Dotfuscator contamos con el atributo [Obsufcation]

Más información

Angular.js para aplicaciones Windows Store

Existe una gran variedad de frameworks javascript, Angular, Ember, knockout, etc. Todos ellos nos proporcionan algo que aquellos que hemos hecho wpf estábamos esperando: Data binding, y la posibilidad de usar patrones como MVVM.

En este artículo doy un vistazo a Angular.js, un framework desarrollado por Google que está dando mucho de que hablar, y, para hacerlo más interesante, he lo empleo dentro del contexto de una aplicación Windows 8, donde las reglas del juego cambian ligeramente.

Instalación y configuración

Para este proyecto, el primer paso es crear una aplicación vacía de Windows 8 con Javascript, podemos usar Visual Studio Express para ello.

Para incluir Angular.js, una cosa que podemos pensar es enlazar directamente a la CDN de angular desde nuestro fichero default.html:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js">
</script> 

Sin embargo nos encontramos con esto:

Usando la CDN de Angular JS

Es decir, no podemos usar una referencia no local para ficheros javascript con lo cual tendremos que descargarlo e incluirlo en nuestro proyecto manualmente. Podríamos además, estar tentados a instalarlo usando nuget, pero en mi opinión agrega demasiados archivos al proyecto.

Como anotación, recomiendo descargar la versión angular.js, no la angular.min.js, ya que tendremos que hacer algunos cambios más adelante.

Una vez tengamos el fichero agregado a nuestro proyecto, si intentamos compilar tendremos una segunda sorpresa:

Excepcion con angular

Hay muchas maneras de resolver este error, pero el que a mí me ha funcionado pasa por editar la función problemática, y sustituir la llamada a la función insertBefore por:

MSApp.execUnsafeLocalFunction(function ()
 {element.insertBefore(child, index);
});

Con este ligero cambio, ya podremos ejecutar nuestra aplicación.

Las vistas

Para mostrar información por pantalla, en vez de construir el HTML manualmente y editar el DOM desde código javascript, simplemente usamos ciertas convenciones para incrustar datos dentro de una plantilla HTML.

<label>Name:</label>
<input type="text" ng-model="yourName" 
placeholder="Enter a name here" />
<h1>Hello {{yourName}}!</h1>

En este caso, el input genera una variable de nombre yourName, que se actualiza en el campo h1, en la región habilitada para ello. Estas variables encerradas entre llaves se pueden usar también dentro de los elementos html, por ejemplo para fijar la propiedad “src” de una imagen:.

<img src="{{item}}" />

No tenemos que preocuparnos por la actualización, ya que al cambiar el contenido del dato, sea cual sea, el valor será actualizado automáticamente. Esto representa una diferencia bastante interesante respecto a otros frameworks como Knockout, donde para que se actualizara el objeto teníamos que definirlo con un tipo muy específico.

Controladores

El controlador se define como una clase javascript, con propiedades y funciones, las cuales luego suelen ser llamadas desde el código fuente, por ejemplo:

function TodoCtrl($scope) {
$scope.todos = [];

$scope.addTodo = function () {
$scope.todos.push({ text: $scope.todoText, done: false });
        $scope.todoText = '';
};

};

En este ejemplo se define un controlador, un campo llamado todos, y un método para almacenar en la lista el valor definido en la variable todoText. El $context es similar al this del standard, aunque con algunas variantes. La vista de este código se parece a algo así:

<h2>Todo</h2> {{todos.length}}
<form ng-submit="addTodo()">
    <input type="text" ng-model="todoText" placeholder="add new todo here" size="30" />
    <input class="btn-primary" type="submit" value="add" />
</form>

A diferencia de lo visto anteriormente, en este código definimos un controlador, accedemos al campo length del objeto todos definido anteriormente, y finalmente llamamos al método como resultado del envío de formularios.

Bucles (y bucles dentro de bucles)

Otra de las cosas interesantes que tiene, es el uso de los bucles para recorrer información:

<ul>
    <li ng-repeat="todo in todos">
        <p>{{todo.name}}</p>
        <span ng-repeat="item in todo.items">
            <img src="{{item}}" /></li>
    </li>
</ul>

En este caso representamos la estructura de todos, y asumiendo que todo es una estructura compuesta, Estos bucles además se pueden anidar, consiguiendo una mayor libertad a la hora de representar datos complejos.

Llamadas HTTP

Para poder hacer llamadas a un servidor externo mediante http solamente necesitamos la url y el método por el cual realizaremos la petición, para efectuar la llamada de la siguiente manera:

$http({ method: 'GET', url: 'http://url' }).
 success(function (data, status, headers, config) {

}).
 error(function (data, status, headers, config) {

});

Este código lo incluiremos en nuestro controlador sin llamadas adicionales, de tal manera que sea ejecutado al cargar el controlador. Si lo hacemos de esta manera nos encontraremos con un bonito error como el que se muestra a continuación:

Http error

Para evitar ese error, hemos de modificar la definición de nuestro controlador:

function TodoCtrl($scope)

De tal manera que ahora además de $scope, recibe $http:

function TodoCtrl($scope, $http)

Resumen

Esto es solamente una primera toma de contacto, y he de decir que la primera impresión ha sido muy buena. La documentación y la cantidad de ejemplos disponibles en internet ayudan también a que la curva de aprendizaje sea simple.

Enlaces adicionales