lunes, 22 de diciembre de 2014

AngularJS: ng-repeat & filter

Hoy veremos cómo funciona el objeto filter en AngularJS. A priori comentar que filter no sólo se usa para filtrar los elementos de una lista en base a unos criterios sino que también se usa para dar un formato diferente a un valor. Puedes ver las diferentes aplicaciones de filter en la doc oficial de angular. En este artículo veremos ejemplos sobre como filtrar una lista (ng-repeat) en base a unos valores introducidos en uno o varios campos. Lo he enfocado desde un punto de vista práctico, explicado con algunos ejemplos sencillos que pueden ayudarte bastante a entender filter y tomar la decisión acertada en tu aplicación.

Si ya has visto algo de ng-repeat y el filtrado básico verás que por defecto puedes aplicar filter en ng-repeat y a medida que escribes en el campo de texto se va aplicando el filtro al resultado.

<input type=”text” ng-model=”query” placeHolder=”introduce un valor”>
<div ng-repeat=”ítem in ítems” | filter: query>
…
</div>
Si nos fijamos en la sintaxi de ng-repeat, podemos más o menos deducir que lo que está haciendo aquí es comparar cada uno de los atributos de ítem con el valor que hay en el campo asociado a “query” y devolver true/false en función de si encuentra dicho valor contenido en alguno de los valores asociados a las propiedades de item. Imaginemos que ítem tiene una propiedad id y otra nombre. Si escribimos “1” en el campo asociado a query buscará el valor 1 tanto en id como en nombre de cada elemento y si el ítem contiene el valor 1 la fila se seguirá mostrando, sino se dejará de ver este ítem… Este funcionamiento por defecto puede valernos en muchos casos y está bien.

Ahora imaginemos que nos interesa crear un campo de texto que no filtre por todas las propiedades del modelo.. en el ejemplo anterior si el ítem tiene id = 11 seguiría apareciendo si introducimos “1” en el campo de filtro (aunque no estemos mostrando el id por pantalla). En este caso podrías salvarlo fácilmente. Si quieres que el filtro aplique únicamente a una propiedad del modelo puedes hacerlo del siguiente modo:
<input type=”text” ng-model=”query” placeHolder=”introduce un nombre”>
<div ng-repeat=”ítem in ítems” | filter: {Name : query} >
Vamos a complicarlo un poco. Tenemos una lista de dos usuarios:
[
{
Id:1,
Name: Carlos,
HairColor: Moreno
Edad = 32
}, 
{
Id:2,
Name: Alba,
HairColor: Rubio, 
Edad = 29
}
]
Queremos tener 2 campos de texto encima de la lista, uno que filter por Name y el otro que filtre por HairColor. Bien, también podríamos hacerlo siguiendo el patrón del ejemplo anterior:
<input type=”text” ng-model=”queryNombre” placeHolder=”introduce un nombre”>
<input type=”text” ng-model=”queryPelo” placeHolder=”introduce un color de pelo”>
<div ng-repeat=”ítem in ítems” | filter: {Name : queryNombre, HairColor : queryPelo } >
Entonces si introducimos los valores “Car” en el filtro nombre sólo se debería mostrar el usuario que contenga Car en el nombre…

¿Qué pasaría si quiero filtrar, por ejemplo, aquellos usuarios que tengan más de 30 años?

Llegado este punto te diría que no sigas complicando la vista... Crea tu propio filter que para eso está. Antes de crearlo veamos un último ejemplo que nos ayudará a entender cómo funciona filter. Podríamos crearnos una función en el scope y llamarla de este modo:
$scope.Mayor30 = function(item){
 var filter = true;
 If (filterMayor30)
           filter = ítem.Edad > 30;
 return filter;
}
<input type=”checkbox” ng-model=”filterMayor30”>Mayor 30
<div ng-repeat=”ítem in ítems” | filter:  Mayor30 >
Verás que siguen apareciendo los 2 porque en el momento que ng-repeat ha filtrado el checkbox estaba desmarcado. Ahora el problema es que si marcas la casilla no se dispara de nuevo ng-repeat porque filterMayor30 no está vinculado en ningún momento a la lista.

¿Qué hay que hacer en este caso? Olvidarse de trabajar en el controlador específico de la vista y crear un filtro. Las buenas prácticas de diseño de software recomiendan crear objetos con responsabilidad única.. por tanto no uses el controlador para incluir funciones de filtrado y evita también complicar la vista como estábamos haciendo al principio del ejemplo… crea tus filters!

Angular permite crear tus propios filtros, vamos a crearnos el filtro del ejemplo anterior, las buenas prácticas recomiendan que crees un module específico para los filters:

(function () {
    'use strict';

    var filterModule = angular.module('cmFilter', []);
    
    filterModule.filter('Mayor30', function () {
        return function (items) {
            var result = [];

            if (items) {
                items.forEach(function (item) {
                    if (item.Edad > 30) {
                        result.push(item);
                    }
                });
            }

            return result;
        }
    });
}());
Tendrás que inyectar el module de filters que has creado en el mismo module donde tengas los controladores que están gestionando la vista donde necesitas el filtro. Aquí asumo que tu controlador está en el módulo principal para no liar la cosa (mala práctica):
    //AngularJS
    var app = angular.module('app', [
         //Angular modules 
         'cmFilter',
    ]);
Finalmente para usarlo en la vista se haría del siguiente modo:
<div ng-repeat="user in users | Mayor30 ">
Puedes pasar parámetros, imagínate que en vez de fijar mayor30 te interesa que el 30 sea un campo donde puedas introducir un valor. El filtro quedaría así:
    filterModule.filter('MayorX', function () {
        return function (items, edad) {
            var result = [];
            if (!edad) edad = 0;

            if (items) {
                items.forEach(function (item) {
                    if (item.Edad > edad) {
                        result.push(item);
                    }
                });
            }

            return result;
        }
    });
En vista creamos un input para recoger el valor que introducirá el usuario:
    <input type="text" ng-model="FilterEdad" placeholder="introduce un valor para edad" /> 
    <div ng-repeat="user in users | MayorX : FilterEdad| orderBy:orderProp" class="row list-item">
Siguiendo esta pauta, podrías llegar a concatenar tantos parámetros como necesites incluso puedes combinar varios filtros.

Te paso algunos links interesantes que pueden ayudarte con este tema:

Hasta aquí el artículo de hoy, posiblemente sea el último ya de este año 2014. A ver qué tal se nos presenta 2015, por lo pronto yo he decidido emprender una aventurilla y cambiar de trabajo tras 10 años en mi actual empresa... espero tocar temas interesantes en mi nuevo puesto y seguir escribiendo a menudo por areaTIC!

Hasta pronto!

martes, 2 de diciembre de 2014

AngularJS rest CRUD $resource vs $http, ejemplo práctico implementado con $resource.

Buenas a todos, hoy veremos cómo realizar un acceso a datos típico CRUD en angular.

Angular como todo framework javascript moderno ya proporciona mecanismos que hace sencilla la integración contra un web api. Al plantearme cómo hacerlo en mis proyectos siempre tenía la duda si crearme servicios inyectando $http e implementar las acciones en cada servicio o bien usar directamente $resource ya que evitas trabajo y simplificas código (resource de base ya implementa un CRUD contra una api rest). Cabe destacar que no siempre tendrás un api rest pura en servidor o tal vez necesitas un control especial de la petición y respuesta donde tal vez sí que tendría alguna ventaja usar $http frente a $resource.

En este artículo usamos $resource porque proporciona una abstracción un nivel por encima de $http, es decir $resource se vale internamente del objeto $http y ya implementa como base un CRUD. Puedes extender la base, el ejemplo más usado es cambiar el verbo del método update para que vaya por PUT. También trabaja internamente $q (promises en angular), por tanto podemos usar promises siempre que hagamos una operación contra servidor.

Vamos al lío, si no dispones de una api contra la que testear este ejemplo, podéis usar alguna pública como esta que os servirá para testear los get. Asumo que tenéis funcionando una aplicación angular con lo básico.

En primer lugar veremos cómo configurar ng-resource:

Tendrás que descargar el paquete e inyectar la dependencia a ng-resource. Puedes obtenerlo aquí.

Ya sabréis que no es recomendable ni óptimo por diversos motivos trabajar directamente sobre el core module, aunque es posible... aquí para simplificar el tutorial inyectamos directamente en el principal.
    //AngularJS
    var app = angular.module('app', [
         //modules 
            'ngResource'
    ]);
El siguiente paso sería crear un nuevo $resource:

Decido crearme un archivo angular.config.resources.js que contendrá toda la definición de recursos que iré necesitando. Podrías optar por organizar el código diferente, tal vez no interese tener un único archivo sino que quieras tener un archivo diferente por recurso… en definitiva para gustos colores.
(function () {
    'use strict';

    var app = angular.module("app");
    // users Resource
    app.factory("UserResource", function ($resource) {
        return $resource(
            "http://jsonplaceholder.typicode.com/users/:Id",
            { Id: "@Id" },
            {
                "update": { method: "PUT" }
            }
        );
    });

//… más resources …

}());
En este bloque de código es importante asegurarse que estás añadiendo los servicios en el module que toca (el que hayas inyectado la dependencia de ng-resource en este caso ‘app’).

Si os fijáis al definir el resource estamos pasándole la url con los posibles queryString de uri que acepta con el prefijo “:” delante, en el segundo parámetro los mapeamos a variables y el tercer parámetro permite modificar el comportamiento de alguno de los métodos base o bien definir nuevos métodos. En este ejemplo hemos especificado que la acción update irá por verbo PUT.

Podéis customizar prácticamente cualquier aspecto de la petición http echarle un ojo a la doc!

Finalmente veremos cómo realizar una llamada al servicio mediante el recurso que acabamos de crearnos.
(function () {

var app = angular.module('app');
app.controller('userController', ['$scope', '$routeParams', 'UserResource', function ($scope, $routeParams, userResource,) { 
        var currentId = $routeParams.id;
        
        $scope.setDinamicContentLoading(true);
        if (currentId) {
            userResource.get({}, { 'Id': currentId }).$promise.then(function (user) {
                $scope.setDinamicContentLoading(false);
                $scope.user = user;
            }, function (error) {
                $scope.setDinamicContentLoading(false);
                alert('Error retrieving user item: ' + error);
            });
        } else {
            userResource.query().$promise.then(function (users) {
                $scope.setDinamicContentLoading(false);
                $scope.users = users;
            }, function (error) {
                $scope.setDinamicContentLoading(false);
                alert('Error retrieving user list: ' + error);
            });
        }
}());
Esta sería la definición de mi controlador para las vistas de usuario, en mi caso uso el mismo controlador para la lista de usuarios que para la vista edición de un usuario concreto. Comentar que no es recomendable añadir controladores directamente al módulo principal de angular, aquí trabajo de este modo por seguir la coherencia del primer paso donde ya hemos inyectado la dependencia en el principal por simplificar el ejemplo.

Si os fijáis, en función de si la ruta contiene un id o no, sé que estoy en una vista u otra y por tanto debería llamar a una acción u otra del servicio.

He visto bastantes tutoriales que ofrecen ejemplos donde no usan promises… úsalos!

Una vez resuelta la llamada asigno el resultado que viene de server al modelo user o users del scope y así ya los tengo disponibles en vista.

Para hacer un Create, Update y Delete sería llamar a userResource.Save(modelo) y ya tendríamos el create y así respectivamente... en la doc está bien explicado.

El tema de setDinamicContentLoading lo uso para el típico loading, comento un poco por encima como lo tengo implementado por si a alguien le interesase la idea. Trabajo con un controlador de layout que gestiona la vista principal (header, mainContent , footer,).. en mainContent cargará la vista que toque según la ruta que vayas navegando con el menú o como quiera que hayas montado la navegación.. Pues bien se trataría de añadir esto a la vista principal dentro del ámbito del layoutController donde "Ajax-loader.gif" es el típico gif animado que puedes personalizarte en internet.
<div ng-show="loading" class="dinamicContentLoading">
   <img src="./img/ajax-loader.gif" style="position:absolute;top:40%;left:45%" />
</div>
La clase css (añadimos comportamiento modal a la capa donde está contenido el gif animado):
.dinamicContentLoading {
    z-index:100;
    border : 1px solid #c0c0c0;
    background:#f0f0f0;
    padding: 0px 10px 10px 10px;
    position:fixed;
    top:0px;
    left:0px;
    height:100%;
    width:100%;
    opacity:0.7;
    filter:alpha(opacity=70);
}
layoutController.js:
  $scope.setDinamicContentLoading = function (value) {
    $scope.loading = value;
  }
Es importante entender que podemos “llamar” al método $scope.setDinamicContentLoading desde el controlador de usuario debido a Angular los contextos están comunicados jerárquicamente lo cual una vez se entiende es bastante potente (…) Lo que hacemos aquí no tiene demasiado misterio ya que es ng-show el que en función de variable $scope.loading mostrará el modal de cargando o no lo mostrará.

Hasta aquí el post de hoy, cualquier duda o discrepancia no te cortes en comentarla a través del blog o si nos sigues en redes sociales. Puedes visitar el archivo de areaTIC tal vez encuentres algún artículo que pueda interesarte.

jueves, 6 de noviembre de 2014

Habilitar site ASP.NET IIS para conectar a SQLExpress

En el artículo de hoy veremos cómo solucionar un problema muy tonto pero que puede hacerte perder algo de tiempo. Si trabajas con el entorno por defecto que plantea Visual Studio 2013 para un site ASP.NET durante la fase de desarrollo no tendrías problema (por defecto localDB e IIS Express). El problema lo tendrás si necesitas por algún motivo ‘deployar’ el site en el IIS local por ejemplo y que acceda a un SQLExpress.

Escenario

Site alojado en IIS Local (no IIS Express) que necesitamos que acceda a una base de datos SQLExpresss también en la misma máquina configurado con seguridad windows. Cuando el site intenta conectar al SQL recibimos una excepción de este tipo. (podría variar dependiendo de la operación que intentes realizar contra la base de datos).
No se puede quitar el base de datos 'x' porque no existe o el usuario no tiene permiso.
o
Se ha denegado el permiso CREATE DATABASE en la base de datos 'master'.

Causa

El problema ya lo dice el mensaje es que no tenemos privilegios para acceder a la base de datos, matizando, mi usuario windows sí que accede… es el usuario asociado al proceso de IIS el que no tiene acceso a SQLExpress. Como sabemos con canalización integrada en versiones superiores a la 7 de IIS el usuario por defecto asociado al proceso de IIS de cada site es el Pool de aplicaciones que es un usuario virtual (built-in).

Solución

En caso que tengamos seguridad Windows en SQL deberíamos dar acceso al usuario asociado al pool de aplicaciones (presupongo que usas SQL Management Studio)...

En SQL cuando gestionas la seguridad Windows puedes seleccionar usuarios de la máquina o dominio como harías en una carpeta del pc. Lo curioso es que en la típica pantalla de Windows para gestionar la seguridad ntfs de un recurso no encontrarás estos usuarios virtuales asociados al pool del site, por mucho que selecciones Entidades de seguridad Integrada (built-in).

Habilitar site ASP.NET IIS para conectar a SQLExpress, figura 1

Este tipo de usuario has de forzarlo (sin realizar búsqueda) de este modo “IIS APPPOOL\NombrePool”. Si el nombre es correcto lo creará al pulsar aceptar, luego ya has de darle los privilegios necesarios a nivel de servidor y en la base de datos que necesite acceder.

Habilitar site ASP.NET IIS para conectar a SQLExpress, figura 2

Más información relacionada en el siguiente enlace:
http://www.iis.net/learn/manage/configuring-security/application-pool-identities

Espero sea útil la información, recuerda visitar areaTIC tal vez encuentres algún artículo que pueda interesarte.

lunes, 6 de octubre de 2014

HTML Orientación Horizontal

Hola de nuevo, desde hace unas semanas estoy creando a ratos como “Home Project” una aplicación crossplatform orientada a cloud y mobile con HTML y javascript. Os planteo un temilla que me encuentro con HTML a la hora de publicar en Windows 8.1.

La aplicación de momento funciona en Android y Windows 8.1 (Store). Consigo ejecutarla como aplicación en ambos entornos (usando cordova / phonegap) pero queda un poco rara comparada con el resto de aplicaciones de la Store de Windows. Con cordova / phonegap hay modos de hacer que se cargue una hoja de estilos u otra en función de la plataforma y ya lo hago para dotar de un estilo más “metro” o más “Android” los mismos ítems pero opino que con esto no es suficiente.

Por defecto un documento HTML crece a largo, es decir, en vertical. A medida que añadimos contenido se van incluyendo filas que generalmente aprovechan el ancho de la pantalla. Es raro encontrarnos scroll horizontal en una página HTML y muy habitual encontrarnos scroll vertical.

Imaginaros que nos interesa que nuestro documento web siempre se ajuste al espacio vertical de la pantalla y crezca a lo ancho (como Falete). No me refiero a leer inclinando 90º la cabeza, la orientación del contenido seguiría siendo la misma. Me refiero a que si tenemos una lista dinámica en vez de ir ubicando los ítems uno debajo de otro los colocásemos uno al lado de otro y el documento se dimensionase horizontalmente según el contenido de la lista.

areaTIC: Html Orientación Horizontal

Esto podría serte útil para aplicaciones de la Windows Store si no usas WinJS y quieres desarrollar una app en HTML. Si tienes un Windows 8 y juegas un poco con alguna aplicación de la Store típica o con las que ya vienen con el sistema operativo, verás que la orientación es horizontal. Ya que estamos, estaría bien que el aplicativo que estamos desarrollando sea capaz de adaptarse fácilmente a un modelo u otro para no tener que hacer un desarrollo específico para cada plataforma ni hacer el mismo layout para todas.

Veamos como he planteado el tema en mi proyectillo:

Listas en horizontal


Imagina una lista de elementos dinámica, seguramente conozcas Bootstrap y sabrás que jugando con la clase col-* en los elementos html de la lista puedes definir fácilmente si quieres 2 columnas por fila o 3 o 4 pero en todo caso siempre se ajustará al ancho por defecto de la pantalla cuando lo superas pasas a nueva fila.

Para conseguir que el ancho del documento crezca a medida que se vayan mostrando ítems tendrás que hacer algo más. Os paso un link donde propone algunos trucos, en mi caso sigo el consejo del autor del artículo y opto por usar un table para mostrar las listas.

Si sustituyes los divs por la estructura de table, tr, td y haces que cada elemento de la lista sea un td nuevo ya lo tienes. Al mostrar los elementos se redimensiona la lista y esto provoca que haya scroll horizontal y hasta aquí bien. El siguiente problema es que el header, footer y resto de contenido de la página para que quede bien se debería ajustar al nuevo ancho de la lista… Dicho de otro modo ha crecido el elemento table pero no el documento html donde está contenida la tabla. Para solucionarlo sería ideal saber cuando ha acabado de mostrar elementos la lista dinámica, obtener el ancho de la tabla y forzar la redimensión del contenedor. Os explico cómo lo he hecho.

Mi aplicación parte de una base desarrollada en Angular que me permite dotar de cierta estructura al código y mil ventajas más que no es el momento de hablar. Para mostrar una lista de elementos dinámica se suele usar ng-repeat. ¿Cómo podría saber cuándo acaba de mostrar la lista? Bien, nos creamos una directiva personalizada y hacemos referencia en el mismo tag donde tengo ng-repeat.

Directiva:
layoutModule.directive('onFinishRender', function ($timeout) {
        return {
            restrict: 'A',
            link: function (scope, element, attr) {
                if (scope.$last === true) {
                    $timeout(function () {
                        scope.$emit('ngRepeatFinished');
                    });
                }
            }
        }
    });
Elemento lista:
<td ng-repeat="photo in photos | filter:query | orderBy:orderProp" ng-class="cssListType()" on-finish-render>
Controlador de la vista donde está ubicada la lista (o jerárquicamente superior, depende como hayas estructurado la aplicación te evitarás tener que crearlo en todos los controladores que tengan listas):
$scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {
            container.style.width = list.clientWidth + 100 + 'px';            
        });
Vale, ahora lo malo es que si siempre uso td para las listas siempre serán horizontales y me gustaría hacerlo variable como comentaba… Yo lo que he hecho es crearme una constante en mi Angular Module correspondiente y una directiva para mostrar el elemento de la lista (td o div) en función del valor de esta constante… por tanto si quiero publicar para Windows cambio la constante y publico, la vuelvo a cambiar y publico para Android.

Rueda del mouse


En mi caso para Windows lo estoy probando directamente instalando en mi máquina el ejecutable ya que es un Windows 8.1 y echo en falta que reaccione al evento de mover la rueda del ratón ya que las aplicaciones originales de la Store lo hacen...

Navegando llegué a este plug-in, se trata de descargarlo y hacer referencia en la página contenedora de la aplicación.

El segundo paso es incluir este script en la página contenedora de la aplicación (puede ser que lo tengas que ajustar en función de cómo estructures el contenido):
      <script>
            $(function () {
                $(window).mousewheel(function(event, delta) {
                    event.preventDefault();
                    var scroll = $("body").scrollLeft();
                    $("body").scrollLeft(scroll - (delta * 20));
                });
            });
        </script>
El siguiente paso sería aprovechar la constante que hemos creado en Angular para determinar que tipo de lista debería usar la directiva... esta misma constante podríamos usarla para hacer que la rueda se comporte como habitualmente o en horizontal según la plataforma y tamaño de la pantalla cliente.

Hasta aquí el artículo de hoy, no te cortes a opinar, proponer alternativas o dudas vía comentarios, mail o redes sociales! Recuerda echar un vistazo al archivo de areaTIC, tal vez encuentres algún artículo que pueda interesarte. Hasta la próxima!

viernes, 5 de septiembre de 2014

Compatibilidad angularJS con Windows 8.1 Store App.

A continuación os mostraré algunos problemas que van saliendo al desarrollar una aplicación de Windows 8.1 Store o Windows Phone 8.1 en AngularJS.
  • Al cargar la aplicación Angular, recibimos una excepción que indica que se está manipulando el documento de forma no segura (angular internamente usa JQuery).

    Error en tiempo de ejecución de JavaScript: No se puede agregar contenido dinámico. Un script intentó inyectar contenido dinámico, o elementos anteriormente modificados dinámicamente, que probablemente no sea seguro. Por ejemplo, el uso de la propiedad innerHTML para agregar un script o HTML con un formato incorrecto generará esta excepción. Recurra al método toStaticHTML para filtrar el contenido dinámico o cree elementos y atributos expresamente con un método como createElement. Para obtener más información, consulte http://go.microsoft.com/fwlink/?LinkID=247104.

    WinJS proporciona métodos para ejecutar código que manipula el DOM de forma segura, es decir funciones donde podemos usar JQuery y no se generaría la excepción… pero usando WinJS nuestra aplicación ya no sería compatible en otras plataformas y seguramente tendríamos que modificar el core module de Angular lo cual es un engorro y si queremos mantenernos actualizados con bower se perderían estos cambios. Os paso una alternativa, que altera algunos aspectos del comportamiento javascript de la aplicación que lo harán compatible con Windows sin necesidad de WinJS, se trata de descargar el .js y referenciarlo antes que inicie Angular.
    https://github.com/MsopenTech/winstore-jscompat
    
  • Otro problema es que los links del menú en Windows Store no funcionaba, al hacer click en algún elemento mostraba el siguiente mensaje:

    No Apps are installed to open this type of link (unsafe)

    Se soluciona añadiendo el siguiente fragmento de código después de iniciar AngularJs (app).
    //AngularJS
        var app = angular.module('app', [
             //Angular modules 
             'cmApp',
             'cmLayout'
        ]); 
    
    //solventa problema con los links del menú en Windows8
        app.config(['$compileProvider', function ($compileProvider) {
            $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|file|ms-appx):/);
        }]);
    
  • El siguiente problema, lo he detectado en el botón de atrás que incorporo en el layout (se muestra en todas las vistas que lo necesitan). Yo estaba retrocediendo a la vista anterior con {windows.history.back();} (sí…. no me había roto los cuernos XD, pero funcionaba en Android y Web). Esto no funciona en la aplicación Windows 8.1, no hace nada al pulsar el botón. Decido controlar el tema desde Angular, podemos capturar el evento routeChangeStart y crearnos un Array donde ir almacenando las páginas por las que navegamos. Lo creo en el contexto del controlador de layout. Back() de este modo será accesible para todos los contextos que se vayan cargando a medida que el usuario navega. Seguramente hayan alternativas más elaboradas (…) pero aquí os dejo esta solución por si ayuda. (a partir de la línea $scope.history =…)
    (function () {
        "use strict";
        var layout = angular.module('cmLayout');
        layout.controller('layoutController', ['$scope', '$location','$route','menu', function ($scope,$location, $route,menu) {
            $scope.isLatMenuVisible = (menu.type === 1);
            $scope.isTopMenuVisible = (menu.type === 0);
            $scope.listItemsOnRow = 1;
            $scope.setListItemsOnRow = function (value) {
                $scope.listItemsOnRow = value;
            };
    
            $scope.history = [];
            $scope.$on('$routeChangeStart', function (event, route) {
                event.preventDefault();
                if (route.$$route)
                    $scope.history.push(route.$$route.originalPath);
            });
            $scope.Back = Back;
            function Back() {
                var item = $scope.history.length - 2;
                if (item >= 0) {
                    $location.path($scope.history[item]);
                }
            }
        }]);
    }());
    
    Y en la vista:
    <button type="button" class="btn btn-default" ng-click="Back()">
    
Hasta aquí el artículo de hoy, hasta la próxima. No olvides consultar el archivo de areaTIC tal vez haya algún tema que pueda interesarte!

martes, 22 de julio de 2014

SQL Server: Resetear valor en columna Identity

En ciertas ocasiones nos puede interesar resetear el valor de una columna identity, por ejemplo, si estamos trabajando en un entorno de preproducción y estamos haciendo pruebas de cargas; tras hacer una inserción de N filas las podemos eliminar pero nos interesaría también resetear el valor de la columna identity. La instrucción DBCC CHECKIDENT nos permite resetear el valor de una columna identity, veamos algunos ejemplos:

-- La siguiente instrucción nos devuelve el valor de la columna identity de la tabla indicada
DBCC CHECKIDENT ('TableName', NORESEED)

-- Devolverá el mensaje siguiente donde 'n' es el valor actual del identity:
-- Comprobación de información de identidad: valor de identidad actual 'n', 
-- valor de columna actual 'n'.
-- Ejecución de DBCC completada. Si hay mensajes de error, consulte al administrador del sistema.

-- Si queremos que en el próximo INSERT el valor de la columna identity sea 1 utilizaremos:
DBCC CHECKIDENT ('TableName', RESEED, 0)

-- En general si queremos que en el próximo INSERT el valor de la columna identity sea n 
-- utilizaremos la instrucción:
DBCC CHECKIDENT ('TableName', RESEED, n-1)

Es importante el utilizar ' ' (comillas simples) en el parámetro TableName; si simplemente especificamos el nombre de la tabla no habrá problemas aunque no usemos las comillas simples pero si trabajamos con esquemas o referenciamos una base de datos es obligatorio el uso de ellas, veamos algunos ejemplos:

-- Esta instrucción se ejecutaría sin problemas
DBCC CHECKIDENT (Tablename, NORESEED)

-- Esta instrucción dará el error:
-- Sintaxis incorrecta cerca de '.'.
DBCC CHECKIDENT (DatabaseName.dbo.TableName, NORESEED)

-- La correcta sería
DBCC CHECKIDENT ('DatabaseName.dbo.TableName', NORESEED)

-- También daría el mismo error
DBCC CHECKIDENT (SchemaName.TableName, NORESEED)

-- La correcta sería
DBCC CHECKIDENT ('SchemaName.TableName', NORESEED)

Y hasta aquí el artículo de hoy, breve pero espero que útil; recordad que dentro de areaTIC podéis encontrar otros artículos interesantes, no dudéis en consultar nuestro archivo, también podéis seguirnos por RSS o las principales redes sociales (twitter, facebook, linkedin...).


LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET

lunes, 26 de mayo de 2014

Javascript, closure, uso this y ámbito variables.

En el post de hoy veremos algunos conceptos bastante básicos pero que es imprescindible desde mi punto de vista dominar si te planteas algún desarrollo serio en javascript. Veremos técnicas “modernas” para encapsular nuestras librerías a la vez que intentaré explicar la diferencia entre ámbito y contexto.

This en javascript representa al contexto donde se invoca al método en el que nos encontramos, por ejemplo si estamos en un ámbito global this contiene información sobre el objeto window pero si hacemos lo mismo dentro de un objeto, this representa el objeto contenedor que llama a la función.

Podrías hacer la prueba y verías que si en ámbito global pones un breakpoint y analizas this, verás que es un objeto Window (navegador) con una serie de atributos. Si haces lo mismo dentro de un objeto, por ejemplo imagina que tienes un objeto persona con una función caminar, si evaluas this dentro de la función caminar verás que se corresponde a la instancia del objeto persona en el que te hallas y los atributos son las variables y métodos que se hayan definido dentro del propio objeto persona. Para llamar a una función situándola en contexto determinado podemos usar el método call o apply que tienen todos los objetos en javascript. Es importante diferenciar contexto y ámbito. Puedes tener 2 tipos de ámbito, global o local mientras que podrías tener infinidad de tipos contextos diferentes (tantos como instancias de objetos tengas).

Respecto al ámbito de las variables podemos definir variables de ámbito global o local. En javascript el ámbito lo marca la función que contiene la declaración de la variable a diferencia de un lenguaje como c# donde el ámbito lo marca el bloque de código. Por ejemplo en c# un If(){} ya tiene su propio ámbito y no podrías usar fuera del bloque del If la variable que has declarado dentro mientras que en javascript si puedes (mejor no lo hagas…). Veamos algún ejemplo en Javascript:
var variableGlobal = "global";
var variableLocal = "local";
algo = true;
function MostrarMensaje() {
   if (algo){
      var variableLocal = "local1";
   }
   alert(variableGlobal + ' ' + variableLocal);
}
function MostrarDeNuevoMensaje(){
   var variableLocal = "local2";
   alert(variableGlobal + ' ' + variableLocal);
}
MostrarMensaje();
MostrarDeNuevoMensaje();
alert(variableGlobal + ' ' + variableLocal);
La función MostrarMensaje sacará un mensaje “global local1, la función MostrarDeNuevoMensaje “global local2” y el alert que está en el contexto global mostrará “global local”. No hay mucho que profundizar simplemente dejar claro que en caso de definir una variable de ámbito local que se llame igual que una global que ya existe dentro de la función donde se ha definido la local, prevalece el valor de la local. No es obligatorio usar var para definir la variable pero sí recomendable sobretodo en ámbito global (…)

Hoy en día está de moda el bundle que es una técnica a través de la cual se fusionan todas las hojas de estilo de un site en un solo documento… hay que ir con cuidado a la hora de desarrollar librerías con las variables globales para evitar que otra librería que a priori no tiene nada que ver modifique el valor de tu variable global. Para evitar esto se suele desarrollar una librería encapsulando el código como si fuese un objeto. Esta técnica es conocida como Closure, y consiste en definir la librería como un objeto singleton. Veamos lo con un ejemplos:
var miLibreria = (function(){
  
})();
Dentro del bloque de código yo definiría los objetos de la librería y luego al final haría un return de este tipo donde devolveré un singleton de mi librería con tantos atributos y funciones como quiera mostrar hacía fuera del objeto.
return { Atributo: _atributo, Atributo2: _atributo2};
Al usar la librería lo haría así:
miLibreria.Atributo 
Veréis que sólo permite acceder a los atributos y métodos que se han definido en el return. De este modo la librería queda protegida y sabemos que nunca se machacarán variables desde fuera de la librería por error. El programador final verá y podrá usar sólo aquellos atributos y funciones que le expongamos en el singleton.

Hasta aquí el post de hoy, recordar que podéis seguir areaTIC en las principales redes sociales. Anímate a participar!

jueves, 15 de mayo de 2014

Javascript, tutorial basado en lenguaje POO

Hace tiempo que tengo ganas de profundizar un poco en javascript, así que hoy me propongo a hacer un artículo rollo tutorial enfocado a gente que domina un lenguaje orientado a objetos como c# o similares y quiere profundizar en js.

Todos en un momento u otro hemos tocado javascript ni que sea para hacer la página del F5 (si aquella que pulsas F5 y sale un alert que te dice por el …. te la hinco) por desgracia con eso no vale para decir que dominas javascript. A día de hoy el lenguaje ha tomado una gran relevancia entre el gremio, y el mundo web en general está evolucionando muy deprisa. Ya no solo se usa javascript para animar algún HTML en cliente o validar datos antes de enviar a servidor… ahora se está empezando a usar en ámbito servidor (por ejemplo node.js) o en cliente pero con un rol mucho más avanzado que el que solíamos otorgar hace unos años (por ejemplo aplicaciones SPA).

Por si no te he convencido a seguir el tutorial en el párrafo anterior, ten en cuenta que compañías como Microsoft en sus últimas versiones de Visual Studio ya dan la opción de desarrollar una aplicación de store para Windows 8 / Windows Phone usando HTML5 y javascript. Aunque mantienen la opción clásica de desarrollar con c#/xaml esto dice mucho sobre la expansión que está teniendo javascript entre los desarrolladores.

Antes de empezar con ejemplos, la primera pega que se encuentra un desarrollador al estar acostumbrado a c# y meterse a aprender javascript es que todo “compila”… (claro es un lenguaje interpretado). En mi caso usaré como IDE Visual Studio 2013 express que ya incorpora intelisense para js con lo que facilita un poco la adaptación y para depurar código uso Chrome.

Bueno me dejo de rollo y empiezo con el tutorial. Lo iré enfocando haciendo símiles entre javascript y un lenguaje POO como c# o java.

Crear una clase


En javascript no tenemos el estamento class pero podemos definir clases de varios modos. Si hacemos uso de this y prototype disponemos de los mecanismos habituales de un lenguaje orientado a objetos como herencia, polimorfismo, etc. Es bastante abierto y hay que ir con cuidado porque dependiendo del modo que decidas usar para definir clases en javascript variará cuantas instancias creas en memoria de un objeto. Recomiendo empaparse bien como funciona Garbage Collector en javascript antes de empezar un desarrollo serio.

En javascript todo son funciones, por tanto una clase en principio será una función:
function Persona(nombre,edad) {
    this.Nombre = nombre;
    this.Edad = edad;
};
La misma definición de la función ya nos hace de constructor y todo lo que encapsulemos dentro de la función precedido de this serán los atributos de nuestra clase.

Instanciar la “clase”:
var persona = new Persona("Carlos", 31);
alert(persona.Nombre);
Como decía hay varios modos de implementar un objeto en javascript, de este modo podríamos tener varias instancias de persona. Otra opción sería crear un singleton (…) que dependiendo del caso podría ser interesante.

Otro tema que no he comentado es que podrías definir atributos (y métodos) como privados usando var en vez de this y luego crear un método público (con this) que haga de getter o setter para asignar valor al atributo lo cual se asemejaría aún más a un lenguaje como C# o java.

Herencia


Se puede implementar la herencia de un objeto usando Prototype. Por ejemplo crearemos una clase Programador que heredará de Persona. Veamos:
function Programador(nombre, edad, lenguaje) {
    this.prototype = Persona.call(this, nombre, edad);
    this.Lenguaje = lenguaje;
};
Veamos como instanciar el objeto:
var programador = new Programador("Carlos", 31, "C#");
alert(programador.Nombre);
Override
Nos puedes interesar como en cualquier lenguaje de programación sobre-escribir un método o atributo de la clase base (modificador override en c#). Lo haríamos del siguiente modo, imaginemos que la clase Persona tiene un método GetEdadEnNumerosRomanos() que por defecto devuelve el valor de la edad en números romanos y queremos que la clase programador lo “pise” y haga lo mismo que el base pero además añada un “-“ al final del resultado. Veamos código:
function Persona(nombre,edad) {
    this.Nombre = nombre;
    this.Edad = edad;
};

Persona.prototype.GetEdadEnNumerosRomanos = function () {
    return "XXXI";
};

function Programador(nombre, edad, lenguaje) {
    this.prototype = Persona.call(this, nombre, edad);
    this.Lenguaje = lenguaje;
};

Programador.prototype.GetEdadEnNumerosRomanos = function () {
    var edadenRomanos = Persona.prototype.GetEdadEnNumerosRomanos.call(this);
    return edadenRomanos += "-";
};
Si os fijáis los métodos los estoy definiendo fuera del ámbito de la “clase”, se podrían definir por ejemplo así:
function Persona(nombre,edad) {
    this.Nombre = nombre;
    this.Edad = edad;
    this.GetEdadEnNumerosRomanos = function () {
        return "XXXI";
    };
};
Según mi punto de vista queda más encapsulado y más mono el problema es que estaríamos creando una función nueva para cada nueva instancia de Persona (raramente te interesará ese comportamiento) mientras que del otro modo la función será única y cada instancia de Persona usará la función (más eficiente). Si nos definimos una instancia de Programador y llamamos a la función GetEdadEnNumerosRomanos nos devolverá “XXXI-“ mientras que si hacemos lo mismo con Persona nos devolverá “XXXI” sin el guión. Con este código podéis hacer la prueba:
var person = new Persona("Carlos", 21);
alert(person.GetEdadEnNumerosRomanos());

var programador = new Programador("Carlos", 31, "C#");
alert(programador.GetEdadEnNumerosRomanos());

Polimorfismo, Boxing-UnBoxing


C# por ejemplo es un lenguaje fuertemente tipado donde para cada variable le especificamos el tipo al declararla. Por ejemplo no podríamos hacer esto.
List<Programador> listaProgramadores = new List<Programador>(){ new Programador(){…}, new Persona(){…});
No compilaría por el segundo elemento de la lista que es de tipo Persona. Si queremos una única lista que almacene las 2 instancias tendríamos que definir una lista de personas en vez de programadores.
List<Persona> listaPersonas = new List<Persona>(){ new Programador(){…}, new Persona(){…});
Esto sí que compilaría, luego si queremos invocar alguna propiedad programador específica tendríamos que hacer un cast.
Programador programador = (Programador)listaPersonas.FistOrDefault();
MessageBox.Show(programador.Lenguaje);
En javascript podríamos asignar objetos de cualquier tipo en la misma lista. Veamos el mismo ejemplo:
var listaPersonas = [new Persona("Carlos", 21), new Programador("Carlos", 31, "C#")];
alert(listaPersonas[0].Nombre + ' ' + listaPersonas[1].Lenguaje);
Esto no quiere decir que el concepto boxing-unboxing no exista javascript, sí que existe lo que no son necesarias conversiones explicitas a la hora de programar.

Interface, Abstract Class


Estos mecanismos en un lenguaje orientado a objetos se usan principalmente para dar comportamiento a los objetos. Es decir, podemos hacer que para que un objeto cumpla una determinada interface tenga implementados una serie de métodos públicos o bien con una clase abstracta podemos obligar también a sus derivadas a implementar ciertos métodos.

Hay modos de definir una clase abstracta en javascript, usaré un ejemplo que he visto por internet y me ha gustado con perros y gatos.
var Animal = Object.subclass(true); // abstracta
Animal.prototype.Dice = function () {
    window.alert(this.Ruido);
};
// definición clases
var Gato = Animal.subclass();
Gato.prototype.Ruido = 'meoooooow';
var Perro = Animal.subclass();
Perro.prototype.Ruido = 'guaoooow';

// uso
var migato = new Cat();
mygato.Dice(); // meooooow!
var migato = new Dog();
miperro.Dice(); // guaoooow!
var mielefante = new Animal(); // error!
La interface como tal no existe pero sí que hay técnicas para saber si un objeto cumple o no determinados comportamientos, intento explicarlo.

Por ejemplo puedes saber si un objeto tiene implementado un método usando este código:
var persona = new Persona("Carlos", 31);
if (typeof (persona.GetEdadEnNumerosRomanos) == "function") {
   alert('el objeto persona contiene este método');
}
Otro modo un poco más elegante sería incorporar una función “can” al prototype de object (todo hereda de object) al que le pasas el nombre de un método y te devuelva si la instancia del objeto que lo invoca implemente el método o no. Al hacerlo en general en Object podremos usarlo en todas nuestras “clases/objetos”.
Object.defineProperty(Object.prototype, 'can', {
    enumerable: false,
    value: function (method) {
        return (typeof this[method] === 'function');
    }
});
Uso:
var persona = new Persona("Carlos", 31);
alert(persona.can("GetEdadEnNumerosRomanos"));
Hasta aquí el primer tutorial de Js espero os resulte interesante. Puedes seguir areaTIC en las principales redes sociales y no te cortes a enviarnos tus críticas, dudas o comentarios. Hasta la próxima!

jueves, 3 de abril de 2014

ASP.NET MVC - Documentar Web Api

En un entorno servidor .NET un buen modo de plantear un proyecto Web Api es usando la plantilla de Visual Studio 2013. En la plantilla, se crea un Area específica con una carpeta Help donde se ubican los controladores, views y clases necesarias para componer las páginas de documentación automáticamente a medida que vayamos añadiendo recursos a nuestra web api.

En caso de usar una versión de Visual Studio de 2012 es posible que tengamos que descargar ASP.NET and Web Tools 2012.2 Update para disponer de la página de ayuda por defecto.

Si tenemos que documentar una web api que no ha sido creada a partir de la plantilla podríamos descargarla de Nuget.
Install-Package Microsoft.AspNet.WebApi.HelpPage
En el ejemplo de hoy crearemos un servicio Artículo y jugaremos con su documentación. En primer lugar elimino el controlador de ejemplo que crea la plantilla (ValuesController).

En siguiente lugar me voy a la carpeta controllers de la root del proyecto y creo un controlador para artículo usando la plantilla de Controlador Web Api con acciones de lectura y escritura. Esto me genera una clase ArticuloController con las acciones CRUD sin implementar.

Opino que como punto de partida para una documentación está bastante bien y si seguimos un patrón se irá documentando prácticamente sola a medida que se añadan nuevos recursos. A continuación expongo temas que me faltarían para tener una documentación útil e iré analizando punto a punto como podríamos hacerlo.

  • Personalizar la apariencia

  • Personalizar la descripción de cada uno de los métodos que se exponen para nuestros recursos y la descripción de la API en general

  • Dar una separación conceptual a la web api como los Namespace en una librería de clases. Por ejemplo en un entorno corporativo puede ser que aproveches la misma web api para servir recursos a diferentes áreas como financieras, recursos humanos, etc... Me interesaría que esta separación se reflejase de algún modo cuando accedes a la documentación.

A continuación os comento como se podría atacar cada uno de los 3 puntos que enumero.

Personalizar la Apariencia


La plantilla de ayuda nos ofrece 2 vistas, index.shtml que permite ver una lista de servicios y api.shtml que nos muestra el detalle de cada servicio.

Editando estos archivos podemos modificar el contenido html y podemos cambiar los estilos que se aplican a los elementos en la hoja de estilos HelpPage.css. De este modo podríamos personalizar el look & fill por defecto que nos ofrece la plantilla.

Personalizar la descripción de servicios y acciones


Hay varias opciones, la más sencilla sería pulsar botón derecho en el proyecto y en el apartado Compilar, se trata de activar la casilla "Xml Documentation file".

La descripción de los servicios y acciones la lee de los bloques “summary” que usamos para documentar nuestros controladores y acciones.
/// <summary>
/// Servicio ...
/// </summary>
public class ArticuloController : ApiController
// GET api/Articulo
/// <summary>
/// Obtiene una lista de …
/// </summary>
/// <returns>…</returns>
[HttpGet]
public IEnumerable<..> Get()
Si hacemos esto al volver a ejecutar el proyecto y cargar la página de nuevo debería mostrarnos esta información en las páginas de ayuda.

Tal vez pueda interesarnos también ocultar una acción (o recurso completo si usamos el atributo a nivel de controlador). Podríamos hacerlo del siguiente modo:
[ApiExplorerSettings(IgnoreApi=true)]
public HttpResponseMessage Get(int id) {  }

Separar la documentación en función de las áreas donde hemos ubicado los controladores de tipo ApiController


  • Generamos una lista con tantos elementos como diferentes áreas haya en el site MVC. Para ello en Global.asax una vez se ha llamado a AreaRegistration.RegisterAllRoutes() obtenemos todas las áreas que hay registradas en RouteTable y almacenamos el resultado en una variable de aplicación.
    this.Context.Application["areas"] = RouteTable.Routes.OfType<Route>().Where(d => d.DataTokens != null && d.DataTokens.ContainsKey("area")).Select(r => r.DataTokens["area"]).ToList();
    

  • Editamos el layout para generar tantos links en el menú superior como areas tenemos en el proyecto de manera dinámica:
    <ul class="nav navbar-nav">
       @{
          List<object> areas =     (List<object>)this.ViewContext.HttpContext.Application["areas"];   
       }
       @ foreach (string area in areas.Where(t => !t.ToString().Contains("HelpPage")))
       {
         <li>@Html.ActionLink(area, "Index/" + area, "Help")</li>
       }
    </ul>
    

  • Por último añadimos un parámetro ApiId a la acción Index del controlador HelpController y filtramos la lista de servicios que se muestran en función del valor que recibimos.
    public ActionResult Index(string apiId)
    {
      ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider();
    
      System.Collections.ObjectModel.Collection<System.Web.Http.Description.ApiDescription> servicios = new System.Collections.ObjectModel.Collection<System.Web.Http.Description.ApiDescription>();
      
    foreach (System.Web.Http.Description.ApiDescription description in Configuration.Services.GetApiExplorer().ApiDescriptions) 
    {
      if (description.ActionDescriptor.ControllerDescriptor.ControllerType.FullName.Contains("Areas." + apiId + "."))
        servicios.Add(description);
    }
    
    
      return View(servicios);
    }
    

Esta es la solución que he encontrado aunque no descarto que haya algún modo más elegante de hacerlo. Tener en cuenta que con esta solución que planteo no estamos autorizando por roles el acceso a la documentación, simplemente la estamos “separando” por áreas. Si queremos que sólo accedan a la documentación aquellos usuarios que están autorizados a hacer una petición a dichos servicios, podríamos llegar a hacerlo creándonos una acción por cada area en HelpController y desde el menú de Layout.shtml modificar los links que se están creando dinámicamente para que cada uno acceda a un controlador.

Tal vez también os pueda interesar crear un cliente de test aprovechando la misma plantilla de ayuda, os paso un link donde explica como hacerlo.

Hasta aquí el artículo de hoy, espero os sea de ayuda. Recordar que podéis participar en areaTIC si queréis o seguirnos a través de las principales redes sociales. Que vaya bien la semana!

martes, 18 de marzo de 2014

REST, HTTP request mediaType

Como sabéis últimamente el término REST se está extendiendo bastante porque es una técnica más ligera en aspectos de comunicación que por ejemplo SOAP y más sencillo de implementar lo cual facilita las cosas para trabajar contra un back-end remoto desde dispositivos móviles con lenguajes como podrían ser javascript.

A priori no sólo vale con exponer un servicio por HTTP y consumirlo para decir que estamos haciendo REST ya que es toda una filosofía y contra más sigues las pautas más RESTFul es tu API y más molas. En resumen REST se basa en HTTP para comunicar 2 extremos así que tenemos varios aspectos que pueden variar y hay recomendaciones o buenas prácticas pero en definitiva todo queda bastante abierto a la persona/s que está implementando la API y te puedes encontrar de todo. Por ejemplo, centrándonos en como ENVIAR datos en una petición/request tenemos varios modos de codificar esta información. El valor típico y por defecto para MediaType es form-url/encoded pero podríamos cambiar este comportamiento en cliente al realizar una petición si la situación lo requiere.

Form-url/encoded no envía nada en el payload (cuerpo de la petición HTTP) se pasa todo codificado en la URL como una colección de clave-valor. Esto puede darte problemas cuando quieres enviar mucha información ya sea en un objeto complejo con sub-objetos y/o listas o directamente un binario pesado.

Hace un tiempo me tocó hacer un cliente a toda pastilla donde no tenía control sobre la parte servidor y estaba obligado a enviar archivos PDF a servidor (verbo GET) codificados en la URL. Todo esto era un requisito para que llegase el archivo a servidor ya que imagino que leía directamente de la URL e ignoraba headers. Poderse hacer se puede pero tal vez si hubiese tenido control del server hubiese trasteado para aceptar codificación MultiData en servidor y desde cliente enviaría la info en el payload lo cual en este caso considero que sería lo recomendable. Además si enviamos mucha info en la URL en .Net por defecto tendremos problemas con el serializador que usa System.Net.Http aquí se explica cómo saltarse la limitación.

Otra pega que veo si quieres enviar de golpe un objeto complejo que a su vez contiene alguna sublista o subobjeto con más atributos. Con json podríamos representar esta jerarquía pero con listas de clave-valor como sería querystring tendríamos que montarnos nosotros algún modo de hacerlo. Aquí la propuesta que pasaba en su día (serialiceListAsParamArray) un poco de aquella manera. Ahora estoy trabajando contra una web api que estamos desarrollando nosotros y no tenemos ese problema ya que el servidor acepta peticiones de todo tipo siempre que el mediaType esté correctamente informado en el header de la petición HTTP.

En su día me creé un cliente genérico que poco a poco voy puliendo, veamos como quedaría el método POST que ahora también contempla que desde cliente se pueda pasar la información en formato json.
private HttpResponseMessage Post(T pValue, bool serialiceListAsParamArray, bool ignoreURLEncondingSizeLimit, bool returnResponseMessage, RequestMediaTypeHeader pMediaType)
{
  try
  {
    HttpContent content = null;

    string pURLEncodedContent = "";
 
    switch (pMediaType)
    {
      #region FormEncodedURL
        case RequestMediaTypeHeader.FormEncodedUrl:
          List> oListTest = new DgestJavaScriptSerializer().GetKeyValuePair(pValue, serialiceListAsParamArray);
          if (!ignoreURLEncondingSizeLimit)
            content = new FormUrlEncodedContent(oListTest);
          else
          {
            foreach (KeyValuePair item in oListTest)
               pURLEncodedContent += string.Format("{0}={1}&", System.Web.HttpUtility.UrlEncode(item.Key), System.Web.HttpUtility.UrlEncode(item.Value));

            pURLEncodedContent = pURLEncodedContent.Substring(0, pURLEncodedContent.Length - 1);

            content = new ByteArrayContent(this.ConvertStringToByteArray(pURLEncodedContent));
            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
          }
          break;
       #endregion

       #region JSON
         case RequestMediaTypeHeader.Json:
           string json = new DgestJavaScriptSerializer().Serialize(pValue);
           content = new ByteArrayContent(this.ConvertStringToByteArray(json));
           content.Headers.ContentType = new MediaTypeHeaderValue(this.GetMediaTypeHeader(pMediaType));
           break;
       #endregion
     }

     HttpResponseMessage response = _Client.PostAsync(_ServiceName, content).Result;
     if (!response.IsSuccessStatusCode)
     {
       throw new Exception(string.Format("{0}: No se ha podido conectar al servicio.", response.StatusCode), new Exception(response.ReasonPhrase)); ;
     }
     return response;
   }
   catch (Exception ex)
   {
     throw ex;
   }
}
Veamos una llamada desde C#:
public ActionResult CalcularProvision(Simulador simulador)
{
  //llamada a Servicio
  simulador = new RESTClient(new Uri(_urlWebApi), "Simulador/Calcular").Post(simulador, RESTClient.RequestMediaTypeHeader.Json);

  return Json(simulador.Provisiones);
}
Hasta aquí el artículo de hoy, como siempre comentaros que podéis seguir areaTIC en las redes sociales y todos vuestros comentarios, críticas y aportaciones son bienvenidas. Que vaya bien la semana!

martes, 11 de marzo de 2014

Excepciones en MVC – HandleErrorAttribute Filter

Esta semana en areaTIC nos disponemos a evaluar las posibilidades que ofrece ASP.NET MVC para la gestión de excepciones. En nuestro caso siempre habíamos optado en entornos WebForms por soluciones globales tipo Application_Error más que ir página a página. En MVC tenemos alguna que otra posibilidad más.

Veamos que opciones tenemos:
  • A nivel local en cada acción de cada controlador con bloque try catch. Implica controlar el error cada vez que creamos una acción en un controlador.

  • A nivel local también podríamos sobre escribir el método OnException del controlador y de este modo evitaríamos tener que escribir un bloque Try/Catch por cada acción.

  • A nivel global si aplicamos mediante FilterConfig un filtro a todos los controladores (por defecto la plantilla de Visual Studio lo aplica) podemos especificar entonces vía web.config una página a la que redirigir la petición cuando se produce un error en un controlador y una vez en la página mostrar el error. Por defecto no se puede gestionar el logging ni tratar diferente los errores según el escenario (por ejemplo llamadas Ajax). Además todo error que se produzca fuera de MVC como podría ser un 404 no pasará por este filtro. Para salvar las 2 primeras limitaciones tendríamos que extender HandleErrorAttribute y para redirigir el 404 a la página de error se podría hacer vía web.config también.

  • Otra opción es usar Application_Error de Global.asx. Tiene sus inconvenientes, el principal es que el evento salta fuera de contexto MVC y por tanto es más complicado personalizar la excepción en función de la acción que la origina.

En nuestro caso nos decantamos por Filters, veamos como extender HandleErrorAttribute. Los pasos para crear un Filter personalizado son muy parecidos a los que haríamos para crear un Helper propio. Creamos una carpeta Filters en el proyecto (si no existe) y dentro añadimos la clase que queremos extender. En este caso heredamos de HandleErrorAttribute e implementamos los métodos base y sobreescribimos el método OnException(). Nos creamos también un método privado para determinar si la petición es Ajax o no ya que en función de esto devolveremos vía MVC la página de error o bien responderemos a la petición inicial Ajax con el código de error correspondiente y el contenido del mensaje para poder gestionar el error en cliente como necesitemos.
namespace AreaTIC.Web.Filters
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class AreaTICHandleErrorAttribute : HandleErrorAttribute  
    {
        public override void OnException(ExceptionContext filterContext)
        {
            if (IsAjax(filterContext))
            {
                filterContext.Result = new JsonResult()
                {
                    Data = filterContext.Exception.Message,
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };

                filterContext.ExceptionHandled = true;
                filterContext.HttpContext.Response.StatusCode = 500;
            }else
                base.OnException(filterContext);
        }

        private bool IsAjax(ExceptionContext filterContext)
        {
            return filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
        }
    }
}
Por último en app_start en el archivo FilterConfig.cs veréis que hay una línea que se encarga de automáticamente añadir el filtro HandleErrorAttribute a cada acción de todos los controladores donde se ha de especificar el nuevo filtro extendido que acabamos de crear.
namespace AreaTIC.Web
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new AreaTICHandleErrorAttribute());
        }
    }
}
Ahora todo correcto si el error se produce durante una llamada Ajax se lanza el evento error: de la llamada Ajax y allí podemos mostrar el contenido del error en un popup o realizar las acciones que creamos oportunas. En cambio si el error se genera desde una petición HTTP normal sin Ajax MVC responde con la página de error que tenemos configurada en Web.Config en la sección CustomErrors.

Hasta aquí el artículo de hoy, como siempre recordar que podéis seguir areaTIC en las redes sociales y son bienvenidos todo tipo de aportaciones y/o comentarios. Que paséis una buena semana!

miércoles, 5 de marzo de 2014

¿Qué es BOM?

BOM Byte order mark se usa en ámbito de codificación de archivos y representa una combinación de bytes que proporciona información sobre como están ordenados el resto de bytes en una secuencia de datos unicode.

En escenarios de intercambio de archivos es recomendable controlar este aspecto y sólo incluir la marca BOM si realmente es lo pactado entre las partes.

El intercambio de archivos contra otra aplicación es un escenario muy habitual, sin ir más lejos ahora consultando este blog tu navegador se está 'entendiendo' con el servidor de donde descarga el contenido para que los archivos sean legibles y poder mostrarte el este artículo... Es difícil encontrar contenido no legible desde un navegador actual en internet ya que cada vez más, los fabricantes de sistemas operativos usan formatos que permiten un margen más amplio de caracteres que ASCII o UTF-8 con lo que apuestan por una codificación global.

Es más fácil encontrarse el problema en un escenario donde tienes que programar una llamada a un servicio web o similar enviando contenido XML y el servidor se queja del BOM al intentar leer el mensaje. Esto se debe a que dependiendo de la codificación, BOM puede ser obligatorio, opcional o no producir ningún efecto. En función del sistema operativo puede ser que trate una situación u otra de modo diferente, por ejemplo en UTF-8 incluir BOM es opcional pero posiblemente algún des-serializador de problemas al leer el contenido si se incluye. Hay codificaciones que si no se ha incluido la información de marcado podrían generar algún carácter no deseado como un espacio en blanco al recibir el fichero.

Por tanto es interesante saber como especificarle al serializador la codificación del contenido y si queremos incluir BOM o no. Veamos un ejemplo sobre como alterar esto en .NET usando XmlSerializer.
  XmlWriterSettings settings = new XmlWriterSettings();
  settings.Encoding = new UTF8Encoding(false);

  using (XmlWriter oWriter = XmlWriter.Create(path,settings))
  {
     XmlSerializer oSerializer;
     oSerializer = new XmlSerializer(typeof(Document));
     oSerializer.Serialize(oWriter,mDocuementSepa);
  }
Mediante XmlWriterSettings podemos acceder al atributo Encoding donde especificamos la codificación. Fijaros en el constructor de UTF8Encoding especificamos el parámetro encoderShouldEmitUTF8Identifier a false para evitar que se incluya BOM.

Si queréis una explicación más técnica sobre que es BOM y como influye exactamente os paso esta página donde está bastante bien explicado y traducido. Hasta aquí el artículo de hoy, recordar que podéis seguir areaTIC en las redes sociales. Si quieres participar en areaTIC puedes ponerte en contacto con nosotros a través del form de contacto. Hasta la próxima!

lunes, 17 de febrero de 2014

SQL Server: Control de transacciones con SQL Profiler

En el artículo de hoy explicaremos cómo controlar y monitorizar la actividad de las transacciones en una base de datos a través de la herramienta SQL Profiler; esto nos puede ser útil para ver el tiempo que tarda la transacción, qué instrucciones se están ejecutando en ella, transacciones anidadas... Los pasos a realizar serán los siguientes:

  • Dentro de herramientas de rendimiento de SQL Server encontramos SQL Profiler, lo abrimos y creamos un nuevo seguimiento (o traza). Por defecto aparece la siguiente pantalla donde podemos indicar el nombre y la plantilla que usaremos (la standard es la predeterminada).

    Transacciones en SQLProfiler, nueva traza

  • Pulsamos en la pestaña “Selección de eventos” y marcamos el check “Mostrar todos los eventos” para ver los eventos disponibles. Marcamos también la opción “Mostrar todas las columnas” ya que las columnas disponibles cambian según los eventos seleccionados (cada uno contiene las suyas, algunas comunes a varios eventos).

    Transacciones en SQLProfiler, selección de eventos

    En este artículo no entraremos en detalle pero podemos ejecutar filtros por columnas para filtrar la traza por base de datos, aplicación, usuario SQL,... En el siguiente enlace podemos encontrar más información sobre SQL Profiler.

  • Vamos desmarcando todos los eventos y mantenemos marcadas todas las columnas de los siguientes eventos:

    1. Del grupo "Stored Procedures" el evento "RPC:Completed" que se dispara cuando se completa una llamada a un procedimiento remoto (por ejemplo, un stored pocedure). En el siguiente enlace podéis encontrar más información sobre el evento RPC:Completed.

    2. Del grupo "TSQL" el evento "SQL:BatchCompleted" que se dispara cuando se completa un lote de Transact-SQL. En el siguiente enlace podéis encontrar más información sobre el evento SQL:BatchCompleted.

    3. Del grupo "Transactions" (que son los eventos relacionados con las transacciones) los eventos "TM: Begin Tran completed", "TM: Commit Tran completed" y "TM: Rollback Tran completed" que se disparan cuando se completa el inicio, commit o rollback de una transacción. En los siguientes enlaces podéis encontrar más nformación sobre los eventos TM: Begin Tran completed, TM: Commit Tran completed y TM: Rollback Tran completed.

    Transacciones en SQLProfiler, eventos seleccionados

  • Una vez seleccionados los eventos y columnas necesarias pulsamos sobre el botón “Ejecutar” para iniciar el seguimiento sobre las transacciones. En este momento es importante destacar que debe llevarse precaución con en el uso de SQL Profiler en entornos de producción ya que puede afectar al rendimiento.

  • Veamos un ejemplo, dentro de SSMS abrimos una nueva consulta y lanzamos las siguientes instrucciones:

    -- Insertamos una fila fuera de una transacción
    INSERT INTO [Address]         
        ([Address]
        ,[City]
        ,[PostalCode])
         VALUES
        ('Paseo de Gracia 25'
        ,'Barcelona'
        ,'08007')
    GO
    
    -- Iniciamos una transacción
    BEGIN TRANSACTION
    GO
    
    -- Insertamos una fila dentro de una transacción
    INSERT INTO [Address]         
        ([Address]
        ,[City]
        ,[PostalCode])
         VALUES
        ('Paseo de Gracia 27'
        ,'Barcelona'
        ,'08007')
    GO
    
    -- Obtenemos valor asignado a la columna identity 
    SELECT IDENT_CURRENT('[Address]')
    GO
    
    -- Hacemos rollback de la  transacción
    ROLLBACK TRANSACTION
    GO
    

  • Observemos la traza resultado de las instrucciones anteriores. En la columna "TextData" podemos ver la instrucción ejecutada y por tanto cuáles están dentro de la transacción, número de "Reads", "Writes", tiempo de "CPU", "Duration"...

    Transacciones en SQLProfiler, traza ejecutada

  • En este punto supongamos que ya hemos analizado el seguimiento pero nos gustaría guardar la selección de eventos que hemos realizado anteriormente por si tenemos la necesidad más adelante de analizar nuevas transacciones. Iremos al menú "Archivo", opción "Guardar como" y seleccionaremos "Plantilla de seguimiento".

    Transacciones en SQLProfiler, guardar plantilla

    Introducimos el nombre de la plantilla (por ejemplo "TemplateTX"), aceptamos y queda guardada. Para próximas ocasiones que queremos hacer un seguimiento sobre transacciones en lugar de usar la plantilla "Standard" (la predeterminada) podremos seleccionar la plantilla que acabamos de guardar.

    Transacciones en SQLProfiler, nombre plantilla

Y hasta aquí el artículo de hoy, espero que lo utilicéis si queréis monitorizar transacciones con SQLProfiler; recordad que dentro de areaTIC podéis encontrar otros artículos interesantes, no dudéis en consultar nuestro archivo, también podéis seguirnos por RSS o las principales redes sociales (twitter, facebook, linkedin...).


LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET

lunes, 27 de enero de 2014

Personalizar plantillas MVC que usa Visual Studio

A día de hoy Visual Studio incorpora plantillas que facilitan bastante el trabajo a la hora de generar controladores y vistas en un proyecto MVC. Estas plantillas en algunos casos permiten asociar un modelo y generan código a partir de los atributos de dicho modelo (scaffolding). Por ejemplo al crear un nuevo controlador, el asistente de Visual Studio nos deja seleccionar diferentes tipos.

Customizar plantillas MVC Visual Studio


El archivo que se genera ya incorpora los métodos para las acciones de listar, editar, crear y eliminar elementos. Por defecto crea los métodos con la firma pero sin implementar.

    public class AreaTICController : Controller
    {
        //
        // GET: /AreaTIC/
        public ActionResult Index()
        {
            return View();
        }

        //
        // GET: /AreaTIC/Details/5
        public ActionResult Details(int id)
        {
            return View();
        }

        //
        // GET: /AreaTIC/Create
        public ActionResult Create()
        {
            return View();
        }

     [...]
Editar estas plantillas puede sernos muy útil para unificar criterios de desarrollo entre el equipo y evitar tener que picar código cada vez que creamos un nuevo apartado. Se podría llegar a crear un controlador que ya incorpore código para el control de errores, paginación de las listas, acceso a datos, etc... Ídem con las plantillas de vistas, puede sernos muy útil personalizarlas.

A continuación veremos como editar estas plantillas para nuestro proyecto.

1) Crearemos dentro del proyecto MVC una carpeta CodeTemplates.

2) Buscamos las plantillas al directorio donde está instalado Visual Studio en la máquina. Lo más sencillo para localizar la plantilla que necesitamos es fijarnos en el identificador para el tipo de plantilla al crear el elemento con el asistente de Visual Studio. Por ejemplo para el controlador que he añadido en el ejemplo el identificador es MVCControllerWithActions (sin el Scaffolder).

Customizar plantillas MVC Visual Studio


3) Copiamos la carpeta entera en CodeTemplates que hemos creado en el primer paso. Si nos fijamos en el contenido de la carpeta hay 2 archivos con extensión ".t4". Uno contiene código c# y el otro vb. En mi caso, una vez copiada la carpeta a CodeTemplates elimino el .vb y me quedo con el .cs dentro de mi proyecto.

4) Editamos el archivo controller.cs.t4 añadiendo un parámetro string page al método Index().
namespace <#= Namespace #>
{
    public class <#= ControllerName #> : Controller
    {
        //
        // GET: <#= (!String.IsNullOrEmpty(AreaName)) ? ("/" + AreaName) : String.Empty #>/<#= ControllerRootName #>/
        public ActionResult Index(string page)
        {
            return View();
        }

   [...]
Con esto ya tendríamos la plantilla editada, Visual Studio antes de buscar en el directorio donde están instaladas las plantillas en la máquina comprobará si hay una carpeta CodeTemplates en el proyecto. En caso que tengamos allí una plantilla para el tipo de archivo que hemos seleccionado, cogerá la plantilla del proyecto en vez de la del directorio de Visual Studio.

Hasta aquí el artículo de hoy. Como siempre animaros a participar, abrir debates, dudas, etc... Recordar que podéis seguir areaTIC en las redes sociales. Hasta la próxima!!

martes, 7 de enero de 2014

SignalR 2.0 en MVC - Ejemplo práctico Horse Race

El post anterior jugamos con el protocolo WebSockets y vimos como realizar un ejemplo en un proyecto ASP .NET MVC. Hoy adaptaremos el mismo ejemplo de la carrera de caballos usando SignalR 2.0.

SignalR en su versión 2.0 es un librería que aporta funcionalidades para gestionar conexiones bidireccionales entre cliente y servidor, en realidad no se puede decir que sea una alternativa a WebSockets sino más bien una librería que facilita este tipo de comunicación en entornos MS. Me explico, si recordamos las limitaciones de WebSockets, no siempre los navegadores aceptan este tipo de protocolo a nivel de transporte. Una de las ventajas que veo en SignalR es que nos aleja un poco del nivel de transporte y se encarga de determinar automáticamente que protocolo se usará en función de las características del cliente que accede a nuestra aplicación web.

En el post anterior, teníamos los siguientes elementos:
  • Controlador estandar para gestionar la vista principal donde se muestra la carrera
  • Vista con un canvas y 2 caballos
  • Script para gestionar la conexión WebSocket en cliente
  • Controlador "webApi" para gestionar la conexión WebSockets en servidor
  • Clase de negocio que gestiona la carrera en servidor

Podríamos partir del mismo proyecto web anterior o crear uno nuevo, lo único que cambiaremos es el script que teníamos en cliente para gestionar la conexión WebSockets y el controlador WebApi que gestiona la conexión WebSocket en server.

Para continuar con el ejemplo es necesario instalar el paquete de SignalR desde Visual Studio (2013) usando el siguiente comando desde la consola del administrador de paquetes de VS -> install-package Microsoft.AspNet.SignalR. Una vez ejecutado este comando si vamos a la carpeta Scripts del proyecto veremos que se han añadido las librerías jquery.signalR-2.0.1.js y jquery.signalR-2.0.1.min.js (la versión podría variar).

Vamos a crear el Hub en servidor. Crearemos una carpeta Hubs en nuestro proyecto, hacemos click botón derecho y seleccionamos "Agregar nuevo elemento" en el menú contextual. Veremos que nos aparece una opción SignalR entre las plantillas, nos situamos en el y seleccionamos tipo de archivo Clase de concentrador SignalR (v.2).
namespace HorseRace.SignalR.Hubs
{
  public class MyHorseRaceHub : Hub
  {
    public void init()
    {
      Race BusinessHorseRace = new Race();
      Task tRace = BusinessHorseRace.InitHorseRace();
      while (!tRace.IsCompleted)
      {
        Thread.Sleep(50);
        List<int> positions = BusinessHorseRace.GetMovement();
        Clients.Caller.message(System.Web.Helpers.Json.Encode(positions));
      }
    }
  }
}
Como veis el código en servidor se simplifica bastante usando SignalR. El siguiente paso es iniciar el Hub que acabamos de crear cuando arranque el site. Si estamos trabajando con MVC 5.0 y Visual Studio 2013 automáticamente al crear el proyecto se añade una clase en la root StartUp donde añadiremos código para mappear e configurar nuestros hubs. En caso de no estar usando la versión 2013 de Visual Studio os tendréis que crear una clase plana vosotros mismos con el siguiente código y asegurarse que se llama desde global.asax al iniciar la aplicación.
[assembly: OwinStartupAttribute(typeof(HorseRide.SignalR.Startup))]
namespace HorseRace.SignalR
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}
Vamos con la parte cliente. Como comentábamos al principio del post sólo tendríamos que cambiar el script de conexión al websocket por el siguiente script:
    $(function () {
        var conexion = $.connection.myHorseRaceHub;

        conexion.client.message = function (message) {
            var positions = $.parseJSON(message);
            initField();
            drawHorseBlanco(positions[0], yC1);
            drawHorseNegro(positions[1], yC2);
        };

        $.connection.hub.start().done(function () {
            $('#btnConnect').click(function () {
                conexion.server.init();
            });
        });
    });
Si pulsamos "Iniciar Carrera" ya tendríamos los caballos compitiendo de nuevo.

Con SignalR podríamos realizar un broadcast desde servidor a todos los clientes conectados de manera bastante sencilla.
En cliente sería añadir el siguiente código:
   conexion.client.broadcastMessage = function (message) {
      alert(message);
  };
En server, añadiría este código al inicio del método init que hemos creado en el Hub:
   Clients.All.broadcastMessage("nuevo cliente conectado");
Esto que nos ha costado 2 líneas de código con SignalR en el ejemplo anterior trabajando directamente con WebSockets se podría haber hecho pero nos hubiese dado más trabajo.

Hasta aquí el artículo de hoy, si alguien estuviese interesado en que le haga llegar el código que contacte conmigo vía linkedin o google. Recordaros, como siempre, que podéis seguir areaTIC en las redes sociales y comentar todo lo que creáis oportuno! Hasta la próxima!!