Marc Rubiño

ASP.NET, C#, AJAX.NET, JavaScript, etc.
SPA con Asp.Net Mvc & Angular

Hace tiempo que quería escribir esta entrada pero la vida me ha dado otras prioridades desde que he vuelto a ser padre. Pero después de varias peticiones me gustaría explicar como combino una aplicación Asp.net Mvc con angular intentando aprovechar las ventajas de tener las vistas en el servidor.

El proyecto

Lo primero que he hecho es crear una solución con dos proyectos uno para la interfaz donde estará angular y otra para los servicios de datos, de esta manera queda más clara la separación de estas responsabilidades de la aplicación.

Proyecto

  • Datos: Proyecto Web API
    • Models: en esta carpeta estaría emulando la parte de negocio y las entidades que usaré en los servicios REST.
    • Controllers: He creado dos controladores para los servicios Uno con para consultar datos maestros y otro para consultar los datos de los concesionarios de coches en los que se basa este ejemplo.

Views

  • Angular: Proyecto ASP.NET MVC
    • Controllers: los controladores típicos de ASP.NET MVC.
      • Home: Controlador de la home donde redirige a la vista principal. Esta vista principal es la encargada de contener las otras vista de angular tipo SHELL.
      • Concesionarios: El controlador que gestiona las vistas con la lista de concesionarios y detalle-edición de los vehículos.
  • Views: Las vistas de MVC donde se encuentra el HTML que necesitamos.
    • Concesionarios: partials views de las diferentes pantallas de la aplicación.
    • Home/Index: vista principal contenedor de las otras vistas.

Index

1
2
3
4
5
</pre>
<div id="main-content">
<div class="bodyPartialView" data-ng-view=""></div>
 <!-- The SPA Views go here --></div>
<pre>
  • Scripts: En la carpeta scripts tendremos todo los ficheros scripts que necesitamos en nuestra aplicación Angular.

Scripts

  •  
    • Libs: librerías de terceros que utilizamos como por ejemplo JQuery.
    • App: donde tendremos los script de la aplicación
      • controllers: los controladores en angular son el código js referente a una vista y su contexto.
      • directives: podemos crear atributos nuevos Html que angular podrá injectar en nuestras vistas, de esta manera podríamos crear nuestros propios controles con HTML y scripts.
      • filters: código que nos permite filtrar o tratar los datos
      • services: servicios disponibles en nuestra aplicación angular, yo por ejemplo tengo un servicio que es el encargado de cargar los datos desde los servicios REST llamado dataContextService.
      • App.js: es el punto de entrada de la aplicación donde está definido el routing de angular.

App.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
demoApp = angular.module('demoApp', [])
    .config(['$routeProvider', function($routeProvider) {
        $routeProvider
            .when('/', {
                templateUrl: '/Concesionarios/List',
                controller: 'ListaCtrl'
            })
            .when('/detalle/:id', {
                templateUrl: '/Concesionarios/Detail',
                controller: 'DetalleCtrl'
            })
            .when('/edit/:id', {
                templateUrl: '/Concesionarios/Edit',
                controller: 'EditCtrl'
            })
            .otherwise({ redirectTo: '/' });
 
    }]);

El enrutamiento de angular es el encargado de configurar las url que se tienen que mapear para servir una vista y que controlador hay que cargar con la misma. Lo bueno de este enrutamiento que acepta tanto código inyectado HTML, como páginas. De esta manera podemos enrutar las vistas de la aplicación angular con las vistas de servidor de MVC.

Ventajas de utilizar las vistas de Servidor

Como he comentado anteriormente la ventaja de utilizar las vistas de servidor es que tenemos la posibilidad de utilizar sus recursos y el sistema de autorización de partes de la página evitando mostrar en cliente las partes privadas de nuestra aplicación, pero no os olvidéis siempre de hacer lo mismo con los servicios. Nadie tendría que acceder a nuestros servicios de datos sin los permisos adecuados.

1. Localización de las vistas en el servidor

Al tener enrutada las vistas desde cliente a las vistas de servidor podemos utilizar los recursos como cualquier otra aplicación ASP.NET MVC. Evitando tener que descargar todos los posibles recurso de todos los idiomas al cliente la primera vez.

</pre>
<h1>@Resources.Language.Title_List</h1>
<pre>

res

2.Autorización de la interfaz de usuario

Otra de las ventajas de utilizar las vistas de MVC es que podemos utilizar el sistema de seguridad que nos ofrece ASP.NET sin problemas. De esta manera solo se descargará la parte de HTML que el usuario tenga permisos y no hará falta administrar la seguridad de la interfaz desde el propio cliente.

Permitir editar solo a los usuarios autentificados:

</pre>
<div data-ng-repeat="coche in item.Coches"><a href="#/detalle/{{coche.IdCoche}}">{{ coche.Marca}}- {{coche.Modelo}}</a>
 @if (Request.IsAuthenticated)
 {
 <button class="btn btn-mini" data-ng-click="edit(coche.IdCoche)"><i class="icon-edit"></i></button>
 }</div>
<pre>

Lista si el usuario no está autentificado

list

Lista si el usuario está autentificado (Aparece el botón de editar)

list2

Conclusión

Bajo mi punto de vista los extremos siempre son malos, no deberíamos tener todo en el servidor ni todo en el cliente, hay que buscar el equilibrio que haga que nuestras aplicaciones puedan aprovechar lo mejor de cada entorno.

Podéis encontrar el ejemplo en : https://github.com/Marckys/AngulaR-ASP.NET-MVC

Cross-Posting: http://mrubino.net/ 

 

 

Posted: 13/2/2014 13:17 por Marc Rubiño | con no comments
Archivado en: ,,
Por qué Knockout no es una librería SPA

Últimamente tengo muchas conversaciones donde se hablan de aplicaciones SPA (Single Page Application) y en el momento de hablar de que librería me gusta más, siempre suele salir a la palestra Knockout y no puedo evitar poner cara de circunstancia, porque esta librería en concreto no me encaja en absoluto como SPA.

Parece ser que no queda muy claro cual su intención o que necesidad cubre. Por eso haré una pequeña comparación sobre diferentes librerías para poder despejar las dudas que se puedan tener sobre ellas.

Que es una aplicación SPA

Una aplicación ”Single Page Application” como bien indica su nombre, es aquella que tiene una pagina principal que se utiliza como contenedor de el resto de páginas. No necesita cargar completamente el documento,  es capaz de separar las vistas de los datos e inyectar el contenido de las paginas o vistas en el contenedor principal. De esa manera puede controlar la carga, la navegación, el histórico, etc. Eso nos permite ofrecer una experiencia de usuario más rica y tener el control total de la interfaz de usuario desde el cliente.

Por eso una buena librería para hacer SPA tendría que darnos una solución completa a estas necesidades:

  1. Routing:  Navegación e histórico.
  2. Datos: Tratamiento de datos con las llamadas AJAX
  3. DOM: interactuar con los objetos del documento.
  4. Mv* : Estructura del código y separando responsabilidades utilizando un patrón Modelo Vista …
    1. Data Binding: es importante que si separamos las vistas del modelo de datos, tengamos un mecanismo para que se comuniquen las dos partes de forma automática y tener un “Two-Way Data Bind” es una buena opción.
    2. Async: Para trabajar con procesos o llamadas a otros módulos lo mejor es utilizar asincrónica y utilizar Promises para facilitar esta tarea.
    3. DI: si utilizamos módulos AMD como componentes se tendría que poder hacer inyección de dependencias.
  5. Testing: esto ya es para nota

La Comparativa

Comparación de las principales librerías que se utilizan actualmente en el desarrollo Web:

Librerías

Datos

DOM

Routing

MV*

DataBind

DI

Testing

KnockoutJs

X

X

X

MVVM

X

X

AngularJs

JQlite

MVW

Durandal

JQuery*

MVW

KnockoutJs*

Require*

X

Backbone

X

X

MVC

X

X

X

* Tiene dependencia con esta librería para su funcionamiento.

  • Knockout:  Como se puede observar esta librería solo nos aporta una manera muy potente de enlazar nuestros datos con las vistas utilizando MVVM y utilizando Two-Way Data Bind. No tiene dependencias  con otras librerías es 100% JavaScript y no abarca todo lo que necesita una aplicación SPA por si sola.
  • Angular: Framework que abarca todo el desarrollo con JavaScript y nos evita depender de otras librerías. Además podemos hacer test unitarios de nuestro código.
  • Durandal: Es una librería que se apoya en otras para poder cubrir todas las necesidades de una aplicación SPA.
    • Knockout para el Data Binding,
    • Require para la inyección de dependencias
    • JQuery para el las llamadas AJAX e interactuar con el DOM.
  • Backbone: Una librería muy liviana, más dirigida en estructurar nuestro código utilizando un patrón MVC que dar cobertura a una aplicación de tipo SPA.

Conclusión

Como se ha podido comprobar en esta comparación Knockout no se puede comparar con las librerías o frameworks SPA, porque solo tiene un objetivo. Que es enlazar nuestro datos con las vistas utilizando un patrón MVVM.

Para conseguir una experiencia SPA completa, tendríamos que combinar Knockout con otras librerías como hace DurandalJS.

Espero que esta reflexión en voz alta deje fuera de las conversaciones sobre SPA a la pobre Knockout ;-)

cross-posting: http://mrubino.net 

 

¿ Qué es un Microsoft MVP ?

Me acabo de enterar que por tercer año consecutivo Microsoft me han reconocido como MVP en la especialidad de ASP.NET-IIS, este reconocimiento para mi es un gran honor que me motiva cada día a seguir aportando mi granito de arena a la gran comunidad .NET y que de vez en cuando nos reunimos para compartir nuestros conocimientos.

Una cosa que me sorprende cada día más, es que muchos de mis compañeros y eso es extrapolable a toda la red, no conocen que es un Microsoft MVP y eso me sorprende porque la comunidad está plagada de recursos que han aportado estos perfiles y la colaboración en muchos foros tecnológicos.

Eso me da que pensar que existen una gran cantidad de profesionales que realmente no se preocupan por investigar más allá de lo que necesitan en su día a día, o que no tienen ese gusanito que te obliga a aprender nuevas tecnologías aunque realmente no las necesites actualmente para tu trabajo. Y es que en estos años he llegado a escuchar de todo sobre los MVP, que si son los que tienen todos los certificados de Microsoft, que es un certificado especial que se puede comprar, etc.

Por ese motivo me gustaría aclarar algunos puntos sobre este tema:

¿ Qué es un Microsoft MVP ?

Para empezar el reconocimiento MVP "Most Value Profesional" es un premio que otorga Microsoft a Profesionales independientes que consideran lideres excepcionales de la comunidad y que comparten con los demás su pasión, habilidad técnica y conocimiento práctico sobre los productos de Microsoft.

Microsoft da este premio para valorar la aportación de una persona durante todo un año a la comunidad bajo sus criterios de selección y que pasan por un líder MVP territorial y que después es definitivamente aprobado por el equipo de producto en Microsoft Corporation "Redmond" de la especialidad en la que se le ha propuesto.

5618_mvp_wallpaper_1024x768

En la actualidad son ya más de 4.000 los MVP que hay en todo el mundo. Representan a más de 90 países, hablan más de 40 idiomas, responden a más de 10 millones de preguntas al año y se les ha distinguido en casi 90 tecnologías de Microsoft. mas...

Qué no es un MVP

Los MVP son profesionales independientes y por consecuencia un MVP no es ni un trabajador de Microsoft , ni un certificado especial, ni nada que tenga que ver con conseguir el reconocimiento con un examen o por la compra de ningún producto Microsoft.

Como ser MVP

Ser un MVP no puede ser nunca un objetivo, tiene que ser la consecuencia de la dedicación a la comunidad. Este premio es un reconocimiento a una trayectoria dentro de la comunidad y es contraproducente tanto para la persona como para la comunidad solo participar para conseguir este reconocimiento ya que se pierde toda visión imparcial y se pierde la efectividad cuando se trata de ayudar a los demás.

Conseguir esta distinción no es sencillo: entre los más de 100 millones de miembros de la comunidad técnica y social de todo el mundo, solo se reconocen en torno a 3.800 MVP cada año.

Mi consejo es participar en la comunidad activamente y no pensar en el premio. cualquiera puede llegar a convertirse en MVP y cualquiera puede proponer a alguien que crea que se lo merece para que Microsoft lo tenga en cuenta para las siguientes nominaciones.

Puedes proponerte a ti mismo u a otras personas en http://mvp.microsoft.com/es-es/nominate-an-mvp.aspx

Conclusión

Yo solo puedo estar orgulloso de ser reconocido con este premio por Microsoft, pero sobre todo estoy orgulloso de participar activamente en la comunidad y crecer profesionalmente con ella y rodeado de tantos amigos virtuales y presenciales. Gracias a todos.

Cross-Posting: http://mrubino.net

Posted: 2/4/2013 15:50 por Marc Rubiño | con 3 comment(s) |
Archivado en: ,
Material JQuery en Windows Stored app

Lo prometido es deuda y os dejo el Material del #JQueryIO que hemos realizado de http://www.desarrolloweb.com espero que lo disfrutéis y me comentéis todas las dudas que os salgan.

Material     streaming
Posted: 14/2/2013 9:41 por Marc Rubiño | con no comments
Archivado en:
Retrospectiva 2012

Este ha sido un año de grandes cambios y experiencias, soy consciente que he tenido olvidado un poco el blog pero eso me ha dejado un poco más de tiempo para participar más intensamente con las comunidades.

Por eso este año he podido conocer más gente en persona o desvirtualizar a otras tantas que tanto hemos coincidido por la red.

Una de mis buenas intenciones para este año, como la de aprender ingles será volver a retomar el blog técnico como anteriormente y poder ofrecer mi granito de arena a la comunidad explicando mis experiencias en el desarrollo de aplicaciones.

Además agradecer a la gente de CampusMVP por ofrecer algunas de mis entradas al mundo anglosajón y de esa manera ampliar un poco mis horizontes virtuales :-)

Otro gran cambio que he sufrido en este año ha sido el reto de formar parte del equipo de Pasiona Consulting y formar parte de Techdencias dándome la oportunidad de participar más activamente en eventos tecnológicos rodeado de un gran equipo de profesionales como son Toni RecioQuique MartínezEduard Tomàs , Isabel Cabezas, Fernando Escolar, Pablo Bouzada, Roger Bardomà, Alex Casquete, Edin Kapic, Jaume Vinyes. Un equipo increíble !!!

Espero que este año como mínimo me vaya igual que este que dejamos hoy.

Hackathon & Meghaton Windows 8

558289_412611465466750_1522753019_n _MG_6639

WP_000007 WP_000009

We Love JS

WP_001539 WP_001541

TechDay Madrid

A8YLvYRCQAEejtU A8TESqOCcAA7YE-

WP_000055 WP_000061

AndorraDotNet

WP_000034 WP_000035

BcnDevConf

WP_000068 WP_000067

Windows Server 2012 Road Show “Sevilla”

WP_000088 WP_000089

Feliz 2013 !!!

Posted: 31/12/2012 15:57 por Marc Rubiño | con no comments
Archivado en:
[Win8 JavaScript] Patrón Promise

Una de las novedades que nos encontraremos a la hora de afrontar una aplicación Windows Store app , es que la mayoría de veces que interactuemos con sus APIS tendremos que hacerlo de forma asíncrona. De esta manera nuestra aplicación no afectará de forma directa al sistema y la respuesta ante el usuario será más ágil y rápida.

Un ejemplo muy gráfico sería acceder a un fichero del sistema:

Windows.Storage.FileIO.readTextAsync(fichero).then(function (contenido) {

//Mostrar contenido

  });

En este ejemplo hemos utilizado la API WinRT para poder acceder al contenido de un fichero de forma asíncrona.  En cuanto se accede al contenido del fichero se lanza la función anónima que está dentro del “then”  mientras la ejecución de nuestra aplicación ha continuado. De esta manera solo mostraremos el contenido del fichero si hemos podido acceder al mismo sin bloquear la aplicación.

Por convención los nombres de las funciones asincrónicas terminan en "Async". De esta manera puedes saber que la ejecución se producirá después que se devuelva la llamada.

Habitualmente se utilizan llamadas asíncronas para los procesos como:

  • Mostrar un cuadro de diálogo de mensaje
  • Trabajar con el sistema de archivos
  • Enviar datos a Internet y recibirlos

¿Cómo funcionan las llamadas asíncronas en las Windows Store app?

Para trabajar de forma asíncrona tanto WinRT com WinJS utilizan el patrón Promise. Este patrón se puede utilizar para gestionar las llamadas asíncronas de una manera facil de seguir y encadenar.

Un objeto Promise devolverá un resultado en algún momento en el tiempo, por ejemplo la función then nos permitirá actuar cuando la promesa se cumpla y para eso disponemos de tres parámetros.

promise.then( onComplete, onError, onProgress);
  • onComplete : función que se lanza cuando se cumple la promesa.
  • onError :  función que se lanza cuando hay un error.
  • onProgress : función que se lanza cuando se notifica un cambio en el progreso de la promesa.

Siguiendo con el ejemplo anterior veremos como capturar los errores y las notificaciones de progreso.

Windows.Storage.FileIO.readTextAsync(fichero).then(
      function complete(res) {
            document.getElementById("result").textContent = res;
      },
      function error(res) {
            document.getElementById("error").textContent = "Error";
        },
      function progress(res) {
            document.getElementById("progress").textContent = "Progress";
 });

Otra función que podemos utilizar es done.

promise.done(onComplete, onError, onProgress);

La diferencia es que en el caso de un error en el procesamiento, la función then devuelve un objeto promise en el estado de error pero no inicia una excepción. Mientras que el método done inicia una excepción si no se proporciona una función de error.

Además then devuelve una promesa lo que nos permite el encadenamiento de promesas, mientras que done devuelve undefined. Por eso se recomienda usar then para una etapa intermedia de la operación (por ejemplo .then().then()) y done para la etapa final de la operación (por ejemplo, .then().then().done()).

Encadenamiento de Promise

Como then devuelve una promesa, puedes encadenar mas de una función asíncrona para su ejecución.

  var divResultado = document.getElementById("result");

  WinJS.xhr({ url: "http://localhost:32999/api/values" })
           .then(function (result) {
               divResultado.innerText = result.responseText;
            return result;
           })
           .then(function (result) {
               divResultado.style.backgroundColor = "green";
           },
             function (error) {
                 divResultado.style.backgroundColor = "red";
                 divResultado.innerText = "Error";
  });

En este ejemplo se puede comprobar como realizar una llamada asíncrona a un servicio de datos externo, en el primer then trataremos los datos, el segundo then destacaremos en la interfaz que los datos se han cargado correctamente y luego tendremos una función  para tratar las excepciones.

Es recomendable encadenar las promesas y no anidarlas para una mejor lectura del código y un mejor seguimiento de los errores.

Si lo preferimos podemos tener una función global para el tratamiento de los errores.

WinJS.xhr({ url: "http://localhost:32999/api/values" })
           .done(function (result) {
               divResultado.innerText = result.responseText;
 });

 WinJS.Promise.onerror = function errorhandler(event) {
         var ex = event.detail.exception;
         var promise = event.detail.promise;
   };

Pero si utilizamos el evento onerror para capturar el error en tiempo de ejecución, estaremos limitando un poco el control de los errores de las llamadas asíncronas.

 

Por último hay que tener en cuenta que para procesos muy largos la mejor opción es utilizar tareas en segundo plano.

Para más información visitar la página oficial de msdn donde hay gran cantidad de información y ejemplos sobre el desarrollo de aplicaciones Windows Store App

cross-posting: http://mrubino.net

 

Update: 22/10/2012
Por si no queda muy claro, Promise no hace que nuestro código sea asíncrono. Promise es una implementación del Patrón Observable y nos ayuda a gestionar nuestras llamadas asíncronas de una manera más sencilla. Las funciones asíncronas son las própias de WinRT acabadas en "Async".

 

 

[Win8] JavaScript - Llamadas a servicio de datos externos “Cross-Domain”

Con la llegada del nuevo sistema operativo de Microsoft, se nos abre un inmenso abanico de posibilidades a los desarrolladores web que no podemos desaprovechar. Ya que podemos crear estas nuevas aplicaciones con HTML 5 y JavaScript para que corran de forma nativa en la nueva interfaz. De esta manera podremos reutilizar todos nuestros conocimientos y nuestra experiencia en realizar aplicaciones que podrán ser consumidas directamente por millones de usuarios potenciales gracias a la nueva tienda de Windows.

Lo primero que tenemos que tener claro es que las aplicaciones web pueden ejecutarse en dos contextos diferentes.

  1. El usuario puede abrir la aplicación web desde el navegador que más le guste como se ha realizado siempre. Y la aplicación se ejecutara en un entorno limitado donde no se podrá acceder a las nuevas Apis que ofrece el sistema “WinRT, WinJS”.

  2. El usuario ejecutara una aplicación de la App Store realizada con HTML y javascript, en este caso la aplicación se ejecutará de forma nativa y en un contexto local. Tenemos acceso a las Apis del sistema para disfrutar de todas las ventajas que nos ofrece Windows 8 accesible directamente desde nuestro código JavaScript.

Si ya tenemos claro estos dos escenarios, tendremos que adaptar un poco nuestras aplicaciones web para que funcionen correctamente como aplicación nativa en Windows8.

Por ejemplo si queremos consumir un servicio externo de datos “cross-domain” sin problemas, podemos utilizar la librería WinJS para hacer una llamada XmlHttpRequest de forma asíncrona y recuperar estos datos de una forma muy sencilla.

 WinJS.xhr({ url: "http://localhost:32999/api/values" }).then(
               function (response) {
                   var json = JSON.parse(response.responseText);
                   json.forEach(function (item) {
                       items.push(item);
            }
        );
 } );

Este ejemplo accede a un servicio WebApi que retorna una lista de datos en formato JSon, hay que destacar que está utilizando el patrón Promise para realizar la llamada de forma asíncrona como casi siempre que interactuemos con las Apis de Windows 8.

Los parámetros que acepta esta función son:

  • type: (opcional). Especifica el Verbo HTTP a utilizar GET, POST, HEAD “petición sin cuerpo de mensaje”. Por defecto la llamada es GET.
  • url: URL del servicio de Datos.
  • user: (opcional). String con el nombre de usuario para la autentificación.
  • password: (opcional). String con la contraseña para la autentificación.
  • headers: (opcional). Objeto cuyas propiedades se usan como nombres de encabezado y los valores de las propiedades se utilizan como valores de estas propiedades del encabezado.
  • data: (opcional). El objeto que se pasa como datos en la llamada.
  • customRequestInitializer: (opcional). Función para utilizar antes de lanzar la llamada XmlHttpRequest.

Un ejemplo de una llamada estableciendo un parámetro en la cabecera, para asegurarse que la respuesta no está cacheada.

WinJS.xhr({
    url: " http://localhost:1489/api/demo ",
    headers: {
        "If-Modified-Since": "Mon, 27 Mar 1972 00:00:00 GMT"
    }
})
    .done(function complete(result) {
        ...
    });

Para más información sobre las propiedades que acepta la cabecera visitar HTTP Response Headers:

Y para finalizar veremos un ejemplo completo de una llamada a un servicio de datos enlazado a un ListView:

  1.  
    1. El origen de los datos que consulta al servicio: Un fichero Datos.js donde se especifica un espacio de nombres “Data” que utilizaremos más adelante para enlazar los datos con el control.

(function () {
    var items = new WinJS.Binding.List();

    WinJS.xhr({ url: "http://localhost:1489/api/demo" }).then(
               function (response) {
                   var json = JSON.parse(response.responseText);
                   json.forEach(function (item) {
                       items.push(item);
                   }
               );
               }
             );

    var publicMembers = { Modelos: items };

    WinJS.Namespace.define("Data", publicMembers);
})();

     2. Enlazamos los datos al control de lista de forma declarativa:

  <div id="lista"  data-win-control="WinJS.UI.ListView"  
             data-win-options="  {
                itemDataSource : Data.Modelos.dataSource,
                layout:{type: WinJS.UI.GridLayout}
         }" >
   </div>

xi1bz

Con este sencillo ejemplo podemos comprobar que sencillo es recuperar los datos de un origen externo sin tenernos que preocupar por el cross-posting ya que se ejecuta la llamada en el contexto local y además se enlaza los datos de forma declarativa con nuestro control HTML.

 

Cross-Posting: http://mrubino.net

JavaScript Visual Studio and TDD

La idea de esta entrada es demostrar lo fácil que puede ser trabajar usando TDD con JavaScript desde nuestro Visual Studio como cualquier otro proyecto de test que tengamos en nuestra solución.

Para este ejemplo utilizaré una aplicación ASP.NET MVC con QUnit el framework de test unitarios que utiliza JQuery y para lanzar los test utilizo directamente Resharper como cuando utilizo otros frameworks como NUnit, MSTest, etc. Debo aclarar que para Visual Studio hay un test runner que lo podéis descargar desde Chutzpah si no tenéis la oportunidad de utilizar Resharper que personalmente me encanta.

Tanto para instalar QUnit como Chutzpah podemos utilizar Nuget desde nuestro proyecto.

TDD

La idea es que necesitamos un Objeto cliente que le podamos especificar diferentes propiedades como puede ser el Nombre, dirección y además añadir sus pedidos.

Test 1

Siguiendo el desarrollo guiado por pruebas, lo primero que tenemos que hacer es una prueba donde intentaremos definir el nombre del cliente.

Lo primero que necesito es poder crear un variable cliente para las pruebas y poderlo utilizar en todas las pruebas y comprobar que cumple con los requisitos. Para eso creo un contexto donde se agruparan todos los test y compartirán la variable cliente. Para esto utilizaré la función module de la librería QUnit.

 

01 ///<reference path="../qunit.js" />
02 module("Client TDD", {
03 setup: function () {
04 this.Client = new Client();
05 this.Client.Name = "Marc";
06 },
07 teardown: function () {
08 this.testData = null;
09 }
10 });

 

Esta función necesita primero el nombre del contexto y luego el objeto usado como el entorno del test. El objeto testEnvironment tiene una función setup que se lanza antes de cada test y podemos utilizar para crear las propiedades que necesitemos utilizar a lo largo de los múltiples test que utilicemos y un teardown que se ejecuta después de cada test que podemos utilizar para limpiar los datos.

Ahora si que podemos crear nuestro primer test.

 

1 test("Test Set Client Name", function () {
2 equal("Marc", this.Client.Name, "el nombre es Marc");
3 });

 

Esta primer test comprueba si el cliente contiene una Propiedad Nombre y si su valor es “Marc” para eso utilizaremos una comprobación de igualdad “equal”.

Yo como he comentado antes utilizaré Resharper para lanzar mis Test. El resultado del primer test tiene que ser negativo como no podía ser de otra manera utilizando TDD.

Resharper nos abrirá un el navegador con el QUnit Test Suite, además de mostrarnos el resultado en nuestro Visual Studio.

Los Errores son clarísimos no tenemos creado el objeto Cliente:

  1. Setup failed on Test Set Client Name: ‘Client’ no está definido.
  2. Died on test #2: No se puede obtener valor de la propiedad ‘Name’: el objeto es nulo o está sin definir.

Pues ahora nos toca implementar el objeto que la prueba necesita para ser pasada con éxito.

Utilizaré un nuevo fichero javascript donde tendré el código que utilizaré en la aplicación y crearé un objeto cliente utilizando el patrón module, con una parte privada y otra pública.

 

1 var Client = function () {
2 var _private = {};
3 var _public = {};
4 _public.Name = "";
5 return _public;
6 };

 

Tenemos que añadir la referencia al script del código en el fichero donde se encuentran los test y ya podemos relanzar la prueba.

 

1 ///<reference path="../qunit.js" />
2 ///<reference path="../Demo/Client.js" />
3 module("Client TDD", { . . .

 

Todo Verde !!! El objeto Cliente ya está cogiendo forma y todo guiados inicialmente por una prueba de lo que esperábamos que fuera.

Test 2

Siguiendo con la definición de nuestro objeto ahora queremos poder definir una propiedad dirección que será objeto un poco más complicado.

 

01 module("Client TDD", {
02 setup: function () {
03 this.Client = new Client();
04 this.Client.Name = 'Marc';
05 this.Client.Address = {
06 street: 'Gran Via',
07 state: 'Barcelona',
08 PostalCode: '08001' };
09 },
10 . . .

 

1 test("Test Set Address", function () {
2 equal({ street: "Gran Via", state: "Barcelona", PostalCode: "08001" },
3 this.Client.Address,
4 'The address is { street: "Gran Via", state: "Barcelona", PostalCode: "08001" }');
5 });

 

Como antes hasta que no añadamos esta propiedad al objeto cliente no pasará la prueba correctamente,

 

1 var _public = {};
2 _public.Name = "";
3 _public.Address = { street: "", state: "", PostalCode: "" };
4 return _public;

 

Pero el test vuelve a fallar !!!

El test falla porque estamos comparando dos objetos que aunque tengan todas las propiedades con el valor igual, son dos objetos diferentes. Par este caso no nos sirve un simple equal y tendremos que hacer una comparación más profunda que nos servirá para objetos y arrays con deeEqual.

 

1 test('Test Set Address', function () {
2 deepEqual({ street: 'Gran Via', state: 'Barcelona', PostalCode: '08001' },
3 this.Client.Address,
4 'The address is { street: "Gran Via", state: "Barcelona", PostalCode: "08001" }');
5 });

 

Test 3

Ahora nuestra intención es hacer un Get-Set y un Count de los pedidos del cliente.

 

01 test('Test Set.Get Orders', function () {
02 this.Client.Set_Order({ Id: "12345", Name: "Rent Car", Total: 237.45 });
03 expect(2);
04 deepEqual(
05 { Id: "12345", Name: "Rent Car", Total: 237.45 },
06 this.Client.Get_Order(1),
07 'The order is { Id: "12345", Name: "Rent Car", Total: 237.45 }');
08 strictEqual(2, this.Client.Orders(), 'The client have 2 orders');
09
10 });

 

Como siempre en TDD la primera prueba falla porque falta definir las funciones en el objeto cliente.

Ampliamos el objeto y pasamos la prueba:

 

1 _public.Set_Order = function (order) {
2 _private.Orders.push(order);
3 };
4 _public.Get_Order = function (index) { return _private.Orders[index]; };
5 _public.Orders = function () { return _private.Orders.length; };

 


Lo que hay que destacar de este test es que hemos definido dos pruebas en el mismo test con expect(2) y hemos hecho una comprobación estricta con resultado y tipo en el count con strictEqual.

Ya tenemos nuestro objeto completo y podríamos seguir con TDD por ejemplo haciendo alguna prueba asíncrona con asyncTest , pero si necesitáis más información sobre QUnit podéis consultar su documentación en http://docs.jquery.com/QUnit

Conclusión

Ya no tenemos excusa para no tener nuestro código JavaScript cubierto con pruebas unitarias garantizando la calidad y un código más mantenible. Con TDD podemos crear nuestros objetos javascript desde nuestros requerimientos y tener directamente garantizado su correcto funcionamiento a partir de nuetros requisitos y necesidades establecidas.

Cross-Posting: http://mrubino.net 

 

 

MVC Exportar Datos a .XLS “Excel Files”

Este truco es uno de los top10 en los foros de MSDN y sigue siendo una de aquellas cosas que no es fácil encontrar una documentación clara y adecuada.

Si hablamos desde la perspectiva de ASP.NET MVC esta tarea se nos simplifica muchísimo porque desde nuestro controlador podemos devolver directamente el contenido de un fichero como cualquier otro ActionResult que tengamos configurado. Para eso tenemos el método File que nos proporciona esa funcionalidad y no tenemos que utilizar directamente el objeto Response como nos pasaba con el clásico ASP.NET WebForms.

 

1 FileContentResult File(byte[] fileContents, string contentType)
2 FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName)
3 FileStreamResult File(Stream fileStream, string contentType)
4 FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName)
5 FilePathResult File(string fileName, string contentType)
6 FilePathResult File(string fileName, string contentType, string fileDownloadName)

 

Para este ejemplo utilizaré la sobrecarga que retorna un FileStreamResult porque lo que queremos hacer es:

Un servicio que recupere los datos de nuestro repositorio, serialice nuestra entidad del dominio en un XML directamente en memoria. Devuelva su contenido especificando que es un fichero Excel y el nombre del fichero que se utilizará para guardar.

Todo esto lo generará dinámicamente en memoria sin tener que tener el fichero Excel físicamente en nuestro servidor.

 

01 public ActionResult ObtenerMisEnviosXmlExcel()
02 {
03 _productosServices = new ProductosServices();
04 var stream = new MemoryStream();
05 var serialicer = new XmlSerializer(typeof(List));
06
07 //Cargo los datos
08 List datos = _productosServices.GetProductos();
09
10 //Lo transformo en un XML y lo guardo en memoria
11 serialicer.Serialize(stream, datos);
12 stream.Position = 0;
13
14 //devuelvo el XML de la memoria como un fichero .xls
15 return File(stream, "application/vnd.ms-excel", "Pedidos.xls");
16 }

 

Para poder serializar nuestra entidad del dominio utilizaremos la clase XmlSerializer que se encuentra en el namespace System.Xml.Serialization.

Cada vez que realicemos esta llamada nos devolverá el fichero Excel creado al vuelo con los datos recuperados de nuestro repositorio.

Una cosa que hay que tener en cuenta al realizar la serialización en XML, es que no es el formato estándar de Excel y tiene que abrir el fichero como datos XML. Eso implica que al abrir el fichero lance un par de avisos que son un poco incómodos más que otra cosa.

He estado probando diferentes librerías para crear ficheros Excel, pero todos te permiten montando el documento por programación, pero no montarlo automáticamente dependiendo de los datos cargados como es el caso del ejemplo anterior.

Si alguien conoce alguna librería que sea capaz de hacerlo directamente o tiene alguna experiencia parecida le invito a que la comparta para poder ampliar esta información y que nos sea de utilidad a todos.

Os recuerdo que también tenéis una entrada relacionada para generar un PDF al vuelo directamente desde una de nuestras vistas recuperando su HTML.

Cross-Posting: http://mrubino.net 

 

Posted: 25/5/2012 9:19 por Marc Rubiño | con 1 comment(s)
Archivado en: ,
Webcat May en BCN !!!

Este miércoles 23 de Mayo se celebra en Barcelona el encuentro mensual que organiza el grupo WebCat "Barcelona web professionals". En estas reuniones se realizan micro sesiones de diferentes tipos y niveles pero con el punto en común que nos une a todos los que trabajamos en entornos orientados a la web.

Micro Sesiones:

Lugar 23 mayo de 7pm a 9pm en Providència, 88, Barcelona. Para más informaciñon http://lanyrd.com/2012/webcat-may
Nos Vemos ;-)

Posted: 16/5/2012 22:17 por Marc Rubiño | con 2 comment(s)
Archivado en:
How to: Insect Invaders

 Desde que asistí al Hack-a-thon de Fuengirola sobre Windows Phone, mi intención ha sido aprovechar la cuenta de suscriptor y publicar algún tipo de aplicación.

Le estuve dando muchas vueltas a que tipo de aplicación podría realizar, mi primera intención era hacer una brújula que apuntara a la Meca para que los musulmanes lo tuvieran más fácil a la hora de orientarse, pero mi sorpresa fue mayúscula cuando me di cuenta que ya habían un par de aplicaciones de este tipo y además una era de pago. A partir de ese momento entendí que cualquier idea que pudiera tener seguro que ya estaba publicado en el MarketPlace.

Pero no desistí en el intento y se me ocurrió hacer un juego en XNA, si tengo que empezar de cero a programar para Windows Phone que mejor que hacer un juego en XNA que no una aplicación con Silverligth que no me gusta nada.

Bueno ya tenía la base y ahora pensar en el juego. Ummm mi primer juego y sin tener ni idea de XNA no puede ser muy complicada de desarrollar. Que mejor que empezar con un clásico que no tiene muchas pantallas y que seguro no puede ser muy difícil de programar como es el Space Invaders.

Cuando tomas una decisión como la mía es ir a la página de Microsoft donde puedes encontrar los ejemplos de todo lo que necesitas para desarrollar tu aplicación.

La Base para el Juego:

  • Pantallas de la aplicación
    • Inicial
    • Juego Principal
    • Menú Pausa
    • Fin de Partida
  • Un fondo que no se tiene que animar
  • Una entidad Nave para el jugador principal
    • Movimiento de derecha a izquierda
    • Disparo “sonido de disparo”
    • Explosión para cuando es alcanzado y Sonido explosión
  • Una entidad Enemigo para crear todos los enemigos con esta base.
    • Movimiento de izquierda a derecha “pero en bloque”
    • Diferentes puntuaciones por tipo de enemigo
    • Disparo
    • Explosión al ser alcanzado y sonido
  • Diferentes niveles para hacer durar un poco el juego
  • Recursos para mostrar las vidas, puntuación y record

¿ Como una persona que nunca ha creado un juego, ni a programado en XNA puede salir exitoso de esta experiencia ?

Yo por ejemplo para mi primer contacto con el tema, miré el curso de un juego con XNA llamado Shootter.

 

Existe una página web sobre desarrollo en Windows Phone indispensable para todo aquel que quiera introducirse en este mundo con gran cantidad de ejemplos que podremos utilizar en nuestros desarrollo.

Pero tener cuidado no tengáis la tentación de publicar directamente el ejemplo de Microsoft como si fuera vuestro que ya no seríais los primeros XD.

Después de esta experiencia que realmente he aprendido mucho he decidido pasar el juego a HTML5 y JavaScript para poderlo utilizar en diferentes plataformas, ya os informaré como me va y si la experiencia es igualmente positiva “seguro que si”.

No os olvidéis de descargar y probar mi juego ;-)

http://www.windowsphone.com/es-ES/apps/c2b100ff-45d8-4972-9d33-8bcbc2f148ba

[Evento] We ♥ JavaScript 2!

El sábado que viene día 28 de Abril, se celebra en Barcelona un encuentro de los profesionales en desarrollo web que apreciamos lo que significa javascript, lo hemos sufrido como todo el mundo, pero también sabemos valorar todo lo que nos aporta. Este evento es organizado por Agile-Barcelona, Runroom y Softonic, un evento de mañana y tarde .

Agenda

10:00 – 11:00 APRETURA – RECEPCIÓN
11:00 – 11:30 Charla sobre CoffeeScript
12:00 – 12:30 Networking
12:30 – 13:30 Charla sobre Game Development
13:30 – 15:00 COMIDA (cortesía de Softonic)
15:00 – 18:00 Workshop Backbone.js
15:00 – 18:00 Workshop PhoneGap.js

* Importante: Los workshops son en paralelo, de modo que te rogamos que únicamente saques ticket en uno de los dos.

Si tenéis pensado asistir daros prisa que solo quedan pocas plazas, yo ya me he registrado ;-)

http://welovejs.es

 

Posted: 20/4/2012 18:16 por Marc Rubiño | con no comments
Archivado en: ,
Microsoft MVP ASP.NET/IIS 2012

Segundo año consecutivo que he recibido la grata noticia desde Microsoft que he sido nombrado nuevamente Microsoft MVP en ASP.NET / IIS para este 2012.

Enhorabuena. Nos complace presentarle el programa de nombramiento MVP de Microsoft® de 2012. Este nombramiento se concede a los líderes excepcionales de la comunidad técnica que comparten de forma activa su experiencia de alta calidad y de la vida real con otras personas. Le agradecemos especialmente la contribución que ha realizado en las comunidades técnicas en el área de ASP.NET/IIS a lo largo del pasado año.

La verdad que es una experiencia inolvidable poder participar en esta comunidad y que se te valore por ello, pero lo más importante y con lo que realmente me quedo es con las personas que he conocido durante todos estos años y que me han ayudado siempre que lo he necesitado y nunca me ha faltado su apoyo. Si los tuviera que nombrar a todos seguramente me dejaría a alguno, pero desde aquí si que me gustaría nombrar a dos personas muy activas en la comunidad que este año se han quedado sin reconocimiento por parte de Microsoft, pero estoy seguro y conociendolos muy bien, sé que ellos seguirán aportando y ayudando a todo el mundo que lo necesite y seran nuevamente nombrados MVP. Un saludo muy fuerte para Toni Recio y José Miguel Torres.

Espero poder seguir aportando mi granito de arena y agradecer a Microsoft este reconocimiento.

 

Cross-Posting: http://mrubino.net/ 

 

 

Posted: 3/4/2012 8:17 por Marc Rubiño | con 1 comment(s)
Archivado en: ,
Exprime la potencia asíncrona en IIS

Una aplicación ASP.NET sobre IIS escala muy bien y tiene muy buen resultado cuando hablamos de peticiones por segundo, pero la cosa puede mejorar cuando hablamos de conexiones concurrentes.

Teniendo en cuenta que cada vez más nuestras aplicaciones son asíncronas, está aumentando la cantidad de peticiones que nuestra aplicación tiene que soportar .

Por defecto ASP.NET 4.o acepta 5.000 peticiones concurrentes por CPU

Peticiones concurrentes por CPU:

Una aplicación ASP.NET en modo integrado bajo IIS7 nos permite configurar cómo administrar los subprocesos y como poner en cola las solicitudes cuando la aplicación está hospedada en un grupo de aplicaciones de IIS.

Los valores applicationPool se aplican a todos los grupos de aplicaciones que se ejecutan en una versión determinada de .NET Framework. La configuración está contenida en un archivo aspnet.config. Hay una versión de este archivo para las versiones 2.0 y 4 de .NET Framework. (Las versiones 3.0 y 3.5 de .NET Framework comparten el archivo aspnet.config con la versión 2.0.)

  • maxConcurrentRequestPerCPU: Especifica cuántas solicitudes simultáneas permite ASP.NET por CPU.
  • maxConcurrentThreadsPerCPU: Especifica cuántos subprocesos simultáneos se pueden estar ejecutando para un grupo de aplicaciones para cada CPU. Esto proporciona una manera alternativa de controlar la simultaneidad de ASP.NET, ya que puede limitar el número de subprocesos administrados que se pueden usar por CPU para atender las solicitudes. De forma predeterminada este valor es 0, lo que significa que ASP.NET no limita el número de subprocesos que se pueden crear por CPU, aunque el grupo de subprocesos de CLR también limita el número de subprocesos que se pueden crear.
  • requestQueueLimit: Especifica el número máximo de solicitudes que se pueden poner en cola para ASP.NET en un único proceso. Cuando dos o más aplicaciones ASP.NET se ejecutan en un único grupo de aplicaciones, el conjunto acumulativo de solicitudes que se realizan a cualquier aplicación del grupo de aplicaciones está sujeto a este valor.

Para configurar nuestra aplicación que trabaja con el framework 4.0 x64

  1. fichero de configuración :
    • %windir%\Microsoft.NET\Framework\v4.0.30319\aspnet.config
  2. Modificar el fichero 
1 <configuration>
2 <system.web>
3 <applicationPool maxConcurrentRequestsPerCPU="5000"
4 maxConcurrentThreadsPerCPU="0" requestQueueLimit="5000" />
5 </system.web>
6 </configuration>

 

Peticiones concurrentes por Aplicación:

Si lo que queremos es controlar la peticiones concurrentes por aplicación nos tendremos que ir a la configuración serverRuntime de nuestro servidor IIS.

  • appConcurrentRequestLimit: Especifica el número máximo de solicitudes que pueden poner en cola para una aplicación. El valor predeterminado es 5.000.

Modificamos la configuración del servidor:

  1. Abrimos el fichero de configuración:
    • %windir%\System32\inetsrv\config\applicationHost.config
  2. Buscar el elemento serverRuntime
  3. Modificar la propiedad appConcurrentRequestLimitque por defecto son 5.000

 

1 <serverRuntime appConcurrentRequestLimit="250000" />

 

Además se puede controlar el tamaño de las cola que utiliza ASP.NET cuando se supera la cantidad de solicitudes por CPU estableciendo requestQueueLimit de processModel.

 

1 <processModel autoConfig="false" requestQueueLimit="250000" />

 

Con todas estas modificaciones podemos controlar mucho mejor el rendimiento de nuestra aplicación y potenciar la gran cantidad de peticiones que se verán incrementadas con el uso de peticiones asíncronas.

Cross-Posting: http://mrubino.net 

 

 

Posted: 21/3/2012 16:54 por Marc Rubiño | con no comments
Archivado en:
MVP Summit 2012

Por primera vez he podido asistir al evento anual que organiza Microsoft dedicado a los MVP de todo el mundo llamado MVP Summit 2012.

Miles de personas reunidas con un mismo objetivo y con la posibilidad de ver las instalaciones que tiene Microsoft en Redmond.

Mi experiencia a este aspecto es totalmente positiva, poder estar una semana con mis colegas y conocer a gente de todo el mundo y especialmente al grupo de Españoles + Andorra, con los que pasé muy buenos momentos. Poder conocer a los integrantes del equipo de producto es otra oportunidad que no se puede explicar.

Nos hablaron de las novedades que se han lanzados durante estos días sin realmente darnos ninguna noticia bomba y pudimos jugar con las nuevas betas a la vez que el resto del mundo.

Está claro que si Microsoft me vuelve a reconocer con el nombramiento MVP nuevamente, no dejaré de asistir a esta convocatoria porque realmente vale la pena.

Y como una imagen vale más que mil palabras…

Posted: 7/3/2012 15:20 por Marc Rubiño | con no comments |
Archivado en: ,,
Optimización Web Sprites CSS

La ventaja de utilizar sprites para nuestros efectos con imágenes, es que no tenemos que esperar a que las imágenes se carguen individualmente, ya que solo tendremos una imagen principal para obtener el mismo efecto.

Piensa la cantidad de descargas que tiene que efectuar el navegador para cada una de las pequeñas imágenes que normalmente utilizamos en nuestras webs. Si todas estas pequeñas descargas la disminuimos en una principal reduciremos el tiempo de descarga de la página de una manera considerable.

El ejemplo más utilizado sería los tres estados de un ratón “normal, al pasar por encima con el ratón y al presionar”. Si utilizas tres imágenes independientes el usuario l pasar el ratón por encima del botón puede experimentar un retardo al mostrar la nueva imagen porque el navegador la tiene que descargar. Pero si utilizamos sprite con CSS este efecto indeseado desaparece a la vez que optimizamos la descarga.

Ejemplo 1: Imágenes por separado.

Imagen 1

Imagen 2

Imagen 3

El CSS para dar efecto al botón.

 

01 .btnSinSprite
02 {
03 width: 211px;
04 height: 64px;
05 background: url(../../Content/btn1.png);
06 border: black solid 0px;
07 cursor: pointer;
08 }
09 .btnSinSprite:hover
10 {
11 background: url(../../Content/btn2.png);
12 }
13 .btnSinSprite:active
14 {
15 background: url(../../Content/btn3.png);
16 }

 

Ejemplo 2: Imagen en Sprite.

Imagen

El CSS para dar efecto al botón.

 

01 .btnConSprite
02 {
03 width: 211px;
04 height: 64px;
05 background: url(../../Content/btnS.png)0 0;
06 border: black solid 0px;
07 cursor: pointer;
08 }
09 .btnConSprite:hover
10 {
11 background: url(../../Content/btnS.png)0 135px;
12 }
13 .btnConSprite:active
14 {
15 background: url(../../Content/btnS.png)0 70px;
16 }

 

Lo importante de utilizar una sola imagen es poder posicionar el fondo mediante la posición x-y, y jugar con el tamaño . De esta manera se muestra la porción de la imagen que necesitamos en cada momento.

Como se puede observar con las imágenes individuales tenemos tres descargas de 3,3KB que han tardado 48ms y con una imagen tipo sprite tenemos solo una descarga de 8,19KB que se ha descargado en 15ms. Una buena mejora con un simple botón imaginaros si optimizamos todas nuestras imágenes de la página.

Ejemplo 1

Ejemplo 2

Con esto ya tenemos un pasito más para poder tener nuestra web un poco más optimizada y para que veáis que esto es una buena práctica os pongo la colección de iconos que utilizan los controles JQuery UI en sus temas.

Cross-Posting: http://mrubino.net 

 

 

Posted: 14/2/2012 10:26 por Marc Rubiño | con 2 comment(s)
Archivado en: ,
Web Deploy – config Transformation

Una de las utilidades que contamos los desarrolladores web en Visual Studio 2010 y que por mi experiencia veo que no se utiliza mucho. Es la transformación de ficheros de configuración.

A quien no le ha pasado que ha realizado un despliegue al entorno de producción y se ha dejado el modo debug activado o la cadena de conexión a la de test. Pues Visual Studio nos permite poder evitar esto de una manera muy fácil y además automática, para que no nos tengamos que preocupar de si lo hemos configurado todo correctamente para el despliegue.

Ficheros de Transformación

Una de las situaciones que habitualmente nos encontramos en los proyectos, es que tenemos que tener diferentes ficheros de configuración para cada uno de los entornos de los que contamos.

No es lo mismo hacer un despliegue para el entorno de Desarrollo que para Pre-Test o Producción. Por eso ahora disponemos de la posibilidad de modificar el fichero de configuración dependiendo de donde queramos publicar nuestra aplicación web.

Lo primero que tenemos que hacer es crear una configuración de compilación que la podemos definir por ejemplo para cada entorno en el que trabajaremos con las diferentes configuraciones.

Podemos crear una configuración nueva o copiar de otra existente.

Una vez que tengamos las configuraciones creadas, hacemos clic con el botón derecho en el fichero de configuración y añadimos los nuevos ficheros de transformación.

Tendemos que tener tantos ficheros de transformación como diferentes configuraciones necesitemos en nuestros despliegues.

¿Qué son los ficheros de Transformación?

Los ficheros de transformación, son ficheros XML que utilizan los atributos XML para especificar que se tienen que modificar o eliminar del fichero web.config.

Por ejemplo el fichero de transformación de la publicación en Release elimina el famoso atributo Debug=true.

 

1 <?xml version="1.0"?>
3 <system.web>
4 <compilation xdt:Transform="RemoveAttributes(debug)" />
5 </system.web>
6 </configuration>

 

XML-Document-Transform

Este espacio de nombres tiene dos propiedades Principales:

  • Locator:Se seleccionan los elementos que coinciden con la expresión XPath combinada.
    • Locator=”Match(key)” – Selecciona los elementos que concidan con el atributo key.
  • Transform:Especifica la transformación de elemento o elementos seleccionados con la propiedad locator.
    • Replace: Sustituye el elemento o primer elemento seleccionado por el informado.
    • Insert: Inserta un nuevo elemento como podría ser una nueva cadena de conexión, al final de la colección.
    • InsertBefore: Inserta un nuevo elemento justo antes del elemento seleccionado.
    • InsertAfter: Inserta un nuevo elemento justo después del elemento seleccionado.
    • Remove: Elimina el elemento o primer elemento seleccionado.
    • RemoveAll: Elimina todos los elementos seleccionados.
    • RemoveAttributes: elimina el atributo especificado de los elementos seleccionados.
    • SetAttributes: Modifica los atributos especificados de los elementos seleccionados.

Los ejemplos más utilizados serían:

  1.  
    1. Modificar el valor de una propiedad personalizada de la configuración por su clave.

 

1 <add key="UrlEscritura" value="http://test/ Solicitudes/ServicioEscritura.svc" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>

 

  1.  
    1. Modificar una cadena de conexión por su nombre: perfecto si atacamos a diferentes bases de datos en cada entorno.

 

1 <connectionStrings>
2 <add name="SqlCon" connectionString="Data Source=server;Initial Catalog=test;" providerName="System.Data.SqlClient" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
3 </connectionStrings>

 

  1.  
    1. Eliminar el famoso atributo de modo Debug cuando compliamos en Release:

 

1 <system.web>
2 <compilation xdt:Transform="RemoveAttributes(debug)" />
3 </system.web>

 

Conclusión

Si nos preocupamos un poco en tener diferentes configuraciones de compilación para nuestros entornos, además de facilitarnos los despliegues y su configuración de forma automática.

También nos evita los típicos errores por descuido que tantos problemas nos suelen dar en los despliegues.

Cross-Posting: http://mrubino.net 

 

 

Posted: 31/1/2012 20:16 por Marc Rubiño | con 5 comment(s) |
Archivado en: ,
Push con SingalR

Últimamente se está oyendo hablar mucho de SignalR en los en tornos de ASP.Net y no es para menos.

Los programadores web estamos acostumbrados a hacer peticiones al servidor “Pull” para poder consultar cualquier cosa y en más de una ocasión hemos tenido que tirar de un timer en el cliente para que cada X-tiempo consulte un recurso del servidor e ir informando al usuario del progreso de una tarea o de los datos que se tienen que actualizar constantemente.

Para evitar esto podríamos utilizar a día de hoy varias opciones como la API de html5 WebSocket que está en fase borrador y ha tenido algún problema de seguridad, podemos utilizar el servidor Openfire con el protocolo XMPP o servidor Node.js con la librería Nowjs . Pero la ventaja que proporciona SignalR frente los otros es que esta especialmente diseñado para aprovechar las características de las aplicaciones ASP.NET MVC tanto el lado del servidor como la parte cliente.

Como empezar

Para empezar tenemos que instalar la librería que tenemos disponible desde Nuget.

Tienes que tener en cuenta que tiene dependencias con la librería JQuery .

El Servidor

En el servidor solo necesitamos una clase que implemente Hub y si queremos hacer una devolución al cliente solo tenemos que añadir una expresión dinámica a Clients que se resolverá en tiempo de ejecución.

 

 
1 public class NotificationHub : Hub
2 {
3 public void Notificar(string valor)
4 {
5 Clients.AddValor("Informamos al cliente");
6 }
7 }

 

El cliente

Recordar la dependencia con JQuery y además hay que poner una referencia a “/Signalr/Hubs” que es donde se crearan los scripts dinámicamente para las llamadas al servidor.

 

 
1 <script type="text/javascript">// <![CDATA[
2 src</span>="/Scripts/jquery-1.7.1.js" type="text/javascript">
3 // ]]></script>
4 <script type="text/javascript">// <![CDATA[
5 src</span>="/Scripts/jquery.signalR.js" type="text/javascript">
6 // ]]></script>
7 <script type="text/javascript">// <![CDATA[
8 src</span>="/Signalr/Hubs" type="text/javascript">
9 // ]]></script>

 

 

1 $.connection.hub.start();
2 var hub = $.connection.notificationHub;
3 hub.AddValor = function (valor) {
4 alert(valor);
5 };

 

1. Abrimos la conexión con el servidor.
2. Inicializamos nuestro hub donde haremos las llamadas.
3. Definimos la función de devolución para actuar cuando el servidor nos informe.

Ya esta !!!! Es súper sencillo !!!!

EJEMPLO

Haré un pequeño ejemplo para que se vea toda su potencia en acción. Imaginaros un control de encuesta donde sea el servidor el que te informe que sus datos se han actualizado y solo permita votar una vez al usuario, toda la lógica estará en el servidor y no en la UI, de esta manera no mezclamos responsabilidades.
Utilizaré la librería jqplot.js para mostrar la gráfica de la encuesta en tiempo real.

Servidor

Primero crearé la parte del servidor donde estará la lógica de los votos.

  

01 public class NotificationHub : Hub
02 {
03 public void Notificar( string valor)
04 {
05 if (valor != null && Encuesta.Instance != null
06 && Encuesta.Datos.ContainsKey(valor))
07 {
08 var clientId = Context.ClientId;
09 if (Encuesta.Usuarios.Any(u => u == clientId))
10 {
11 // El usuario ya ha votado no hay que actuar
12 // ni informar de actualizaciones
13 }
14 else
15 {
16 Encuesta.Usuarios.Add(clientId);
17 Encuesta.Datos[valor]++;
18 var resultado = Encuesta.Datos.Keys.Select(
19 key => new List</pre>
20 ()
21 <pre>
22 {
23 key, Encuesta.Datos[key]
24 }).ToList();
25
26 // Informamos al cliente
27 Clients.AddValor(resultado);
28 }
29 }
30 }
31 }

 

Esta clase controla si el usuario ya ha votado y si no lo añade a la lista para no permitir votar la próxima vez que llame el mismo cliente y como se puede observar, tenemos acceso al identificador del cliente para controlar quien es el que hace la llamada, pero además podemos acceder al dentity para hacer un seguimiento más exhaustivo del usuario y sus credenciales.

Luego si el voto es de un elemento correcto le incrementa el número de votos y retorna a todos los clientes conectados los nuevos datos de la encuesta actualizada.

El cliente llamara a Notificar(valor) para informar del voto y estará en espera que el servidor actualice los datos con AddValor(resultado).

Cliente

Tendremos una vista con varios radio buttons para seleccionar las opciones de la encuesta y un botón que lanzara la llamada al servidor con la selección del usuario.

 

 
01 $(function () {
02 inicializarEncuesta();
03 $("#btnSendNotificacion").click(function () {
04 var voto = $('input:radio:checked').val();
05 hub.notificar(voto);
06 });
07 $.connection.hub.start();
08 var hub = $.connection.notificationHub;
09 hub.AddValor = function (valor) {
10 $.jqplot('chart1', [valor], chartOption()).replot();
11 };
12 });

 

Si el servidor devuelve nuevos datos “AddValor” entonces repintaremos el gráfico con la nueva información.

De esta manera todos los usuarios conectados a la encuesta reciben las actualizaciones en tiempo real.

Conclusión

SignalR es un Framework potente y fácil de utilizar que nos permite mantener conexiones abiertas con el servidor de ASP.NET.
Con este tipo de librerías podemos empezar a realizar aplicaciones realmente colaborativas y en tiempo real, donde se definen mejor las responsabilidades gracias a las llamadas Push y nos ayuda a no agregar lógica de negocios en nuestras UI.

 

Cross-Posting: http://mrubino.net 

 

 

Posted: 17/1/2012 21:10 por Marc Rubiño | con 2 comment(s)
Archivado en:
Deserializar JSon a tipo anónimo .Net

En ciertas ocasiones podemos necesitar deserializar un objeto pasado desde un cliente en formato JSon a un tipo .net anónimo. Por ejemplo si utilizas MongoDB con el driver NORM y pretendes filtrar u ordenar de una manera dinámica, es difícil pasar estos objetos a la query para poder generar un filtro dinámico.

Para hacernos una idea esta sería una consulta paginada y con un filtro sencillo con NORM:

1 //NoRM anonymous objects:
2 return GetRepository().GetCollection("Personas")
3 .Find(
4 new { Nombre = Q.IsNotNull() }, //Where
5 new { Fecha = OrderBy.Descending }, //OrderBy
6 10, // Nº elementos de la secuencia "Skip"
7 0 // Primer elemento de la secuencia "Take"
8 );

 

Esta consulta nos devolvería las 10 primeras personas con Nombre que no sea null.

Tanto al utilizar los tipos anónimos como en las consultas LinQ se tiene que especificar la propiedad por la que se quiere filtrar u ordenar y eso nos limita a la hora de intentar hacer estas consultas de forma dinámica.

Parara hacer una prueba crearemos un tipo específico para utilizar en las consultas desde javaScript.

Lo ideal sería:

1 public class QueryRequest
2 {
3 public int Pagina { get; set; }
4 public int Registros { get; set; }
5 public object Orden { get; set; }
6 public object Filtro { get; set; }
7 }

 

Con este tipo nos pasarían como parámetros lel número de página, la cantidad de registros y además un object para filtrar y otro object para ordenar.

Pero esto no funciona porque NORM no lo reconoce como tipo anónimo y si lo intentamos pasar como string tampoco funciona.

Ahora solo nos queda intentar deserializar directamente nosotros el objeto JSON en un tipo anónimo y para eso utilizaremos el tipo dynamic que tenemos disponible desde c# 4.

Para eso solo tenemos que deserializar un texto con datos en formato JSon utilizandoJavaScriptSerializerque te permite utilizar un tipo T.

1 var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
2 var ObjetoAnonimo = jss.Deserialize(strJson);

 

Con estas dos líneas lo tenemos solucionado y el nuevo tipo podría quedar de esta manera para facilitar la entrada de los datos como string y la salida como objeto dinámico.

01 public class QueryRequest
02 {
03 public int Pagina { get; set; }
04 public int Registros { get; set; }
05
06 // input string - output dynamic
07 private string orden;
08 public dynamic Orden { get { return DeserializarJSon(orden); } set { orden = value; } }
09
10 // input string - output dynamic
11 private string filtro;
12 public dynamic Filtro { get { return DeserializarJSon(filtro); } set { filtro = value; } }
13
14 private dynamic DeserializarJSon(string strJson)
15 {
16 var jss = new JavaScriptSerializer();
17 dynamic resultado;
18 try
19 {
20 resultado = jss.Deserialize(strJson);
21 }
22 catch (Exception)
23 {
24 resultado = new { };
25 }
26 return resultado;
27 }
28
29 }

 

Ahora nuestro objeto es capaz de devolver un tipo anónimo al consultar la propiedad Filtro y Orden.

01 public IEnumerable FindFiltradoDinamico( QueryRequest datos )
02 {
03 //NoRM anonymous objects:
04 return GetRepository().GetCollection("Personas")
05 .Find(
06 datos.Filtro as object,
07 datos.Orden as object,
08 datos.Registros,
09 datos.Pagina * datos.Registros
10 );
11
12 }

 

Ahora si tenemos las consultas preparadas para aceptar parámetros dinámicos.

01 public ActionResult Index()
02 {
03 var datos = new QueryRequest()
04 {
05 Pagina = 0,
06 Registros = 10,
07 Filtro = " { Edad : { '$gt': 15 } } ", //mayor de 15 años
08 Orden = "{ Nombre : -1}" // 1 Ascendente - -1 Descendente
09 };
10
11 var f2 = repositoryPersona.FindFiltradoDinamico(datos);
12
13 return View();
14 }

 

 

Cross-Posting: http://mrubino.net

 

 

 

Posted: 5/12/2011 11:26 por Marc Rubiño | con no comments
Archivado en: ,
Vistas & View Engines en ASP.NET MVC

Partiendo de que la intención de MVC es separar las responsabilidades de cada componente, me gustaría explicar cual es la responsabilidad de las vistas y como utilizarlas en ASP.NET MVC.

Lo que primero nos choca a los programadores que procedemos de los formularios web, es que han desaparecido los eventos y el famoso ciclo de vida, y eso se debe precisamente que ASP.NET MVC es mucho más natural en los protocolos HTTP y HTML en su tratamiento.

Mvc vs WebForms

Como se puede apreciar en la imagen los formularios web se basaban en los eventos para procesar una petición, entrar en el ciclo de vida del documento, tratar el evento, pintar los controles y devolver el resultado.

Sin embargo las peticiones en MVC son mucho mas simples y respetuosas con el protocolo HTTP. La petición la recibe el motor de rutas que mediante la URL decide cual es el controlador que la debe procesar, el Controlador puede consultar al modelo si es necesario y posteriormente devuelve un ActionResult que puede ser un fichero, datos en formato JSon, una vista, etc.

Vistas

Como ya he comentado la vista encapsula la lógica de presentación y NO tiene que contener lógica de la aplicación ni código de recuperación de datos.

Las vistas no son ficheros físicos ligados a una URL como en los formularios web. Cuando queríamos consultar un formulario teníamos que poner su ruta física www.miaplicacion/personas.aspx En MVC es el controlador el que decide que vista servir y eso facilita que las url sean descriptivas y que los buscadores puedan indexar mejor las páginas de nuestra aplicación “SEO Friendly“.

ViewBag:

Las vistas pueden recibir datos desde el controlador gracias al ViewBag que devuelve un diccionario de datos dinámicos. La gran diferencia con ViewData de las versiones anteriores de MVC, es que ViewBag aprovecha la opción de c#4 para generar tipos dinámicamente y evita tener que hacer conversiones en la vista para obtener el tipo adecuado de los datos.

En el Controlador: Definimos la propiedad que queremos pasar a la vista y el dato

1 ViewBag.Message = "Welcome to ASP.NET MVC!";

 

En la vista: desde la vista recuperamos el dato de una forma muy fácil.

1 <h2>@ViewBag.Message</h2>

 

ViewData vs ViewBag: la gran diferencia es que ya no tenemos la necesidad de hacer conversiones de los datos para poder tratarlos correctamente

1 @*Tipo Fecha con tipos dinámicos*@
2 <h1>@ViewBag.FechaVieBag.ToShortDateString()</h1>
3
4
5 @*Tipo Fecha con ViewData*@
6 <h1>@(((DateTime)ViewData["Fecha"]).ToShortDateString())</h1>
7

 

Tipos de Vistas de las que disponemos:

  •   View Page: Vista principal.
  • LayoutView: Pagina Maestra.
  • ViewContentPage: Vista que utiliza una página Maestra predefinida.
  • Partial View: Vista que se utiliza desde otra vista y no se puede llamar directamente. Como se utilizaban los user controls en los webForms. La vista parcial tiene acceso a su ViewData y al dela vista primaria, pero las actualizaciones de los datos de la vista parcial solo afectan a su viewData y no a la de la vista primaria.

View Engines

ASP.NET MVC utiliza view engines para generar las vistas y desde MVC3 disponemos de dos motores de vistas incluidos para utilizar directamente.

  • ASPX: Es el motor de vistas de ASP.NET con tipos personalizados “ViewPage, ViewMasterPage y ViewUserControl” que heredan de los tipos de páginas existentes .aspx, .ascx, .master.
  • Razor: Motor de vistas más cercano para los programadores de C# o VB
  • Otros:

Convenciones

Hay un par de convenciones que nos afectan al trabajar con las vistas y nos ahorran interminables ficheros de configuración.

  • Return View(): no tenemos que especificar explícitamente que vista estamos devolviendo, porque si no lo hacemos utilizará el nombre de la acción para encontrar la vista. Este ejemplo retorna la vista Create.
1 // GET: /Peliculas/Create
2 public ActionResult Create()
3 {
4 return View();
5 }

 

  • Estructura Vista – controlador: Los controladores se tendrán que llamar MyNombreController y las vistas estarán en una carpeta llamada MyNombre dentro de la carpeta Views. De esta manera el controlador encontrará la vista sin problemas.

En esta imagen las extensiones de los ficheros son .cshtml porque he utilizado el motor de vista Razor en C#, si utilizara VB seria .vbhtml y si utilizara el motor de vista ASPX sería (.aspx, .ascx, .Master)

Creo que con esto hemos visto todo lo que tiene que ver con las vistas en MVC 3

Cross-Posting: http://mrubino.net

 

 

Posted: 29/11/2011 12:52 por Marc Rubiño | con no comments
Archivado en:
Más artículos Página siguiente >