martes, octubre 09, 2012

Qué tecnología de UX usar para una nueva aplicación (Silverlight/WPF, Metro ó HTML5)

Etiquetas de Technorati: ,,,

Fuente: http://www.telerikwatch.com/2011/09/how-to-pick-your-platform-silverlight.html

Lanzamiento de Visual Studio 2012

El pasado jueves 4 de octubre asistí al evento de lanzamiento del nuevo Visual Studio 2012. En este post quiero resumir lo más destacable.

9:30 Bienvenida David Carmona (Microsoft)

  • Tendencias actuales en el mundo del software: movilidad + cloud.
  • Apps modernas: centradas en el usuario (no tanto en el proceso de negocio), social (integración con otros: Yammer, Twitter, Facebook…), democratización de los datos de la empresa de forma que estén integrados en los procesos de todos los usuarios (Bigdata), y, que permitan la mejora continua.
  • VS2012, herramienta para el desarrollo de apps modernas y ALM (Gestión del ciclo de vida de las aplicaciones).
  • Apps desktop vs apps para dispositivos conectados. Las primeras siguen siendo los reyes para entrada de datos. Para las segundas está emergiendo con fuerza HTML5.
  • Typescript (alineado con ECMAScript 6): capa sobre javascript que permite intellisense, refactoring…
  • Vuelven las herramientas para Compact Framework (en VS2010 se habían sacado).
  • Phonegap y Mono no acaban de cuajar.
  • LightSwitch se integra en el IDE de Visual Studio con muchas mejoras.
  • SignalR (NodeJS) es una capa de abstracción sobre Web Sockets para comunicación bidireccional entre cliente y servidor.
  • Ciclo de vida de las aplicaciones modernas: feedback continuo, calidad continua, entrega continua.

10:30 Desarrollo de aplicaciones Modernas. Caso Estudio: Acciona

La empresa Acciona (apoyados por Plain Concepts) ha desarrollado su propia aplicación para el control en tiempo real de las plantas de generación de energía: SCADA. A destacar:

  • NoSQL
  • “Tabletas, Windows 8 y la interfaz Windows Store abren las puertas definitivamente a la movilidad”.
  • Sensores (GPS, Giroscopios…)
  • Bigdata
  • Hadoop (gratuito)
  • image
  • Metodología ágil (SCRUM)

12:00 Definición: Requisitos y Planificación continua (Danisoft y Microsoft)

(Ésta me la perdí…)

12:30 Desarrollo: Entrega continua / Habilitando la Calidad de forma continua Rodrigo Corral (Plain Concepts)

  •  

    Tendencia actual: Agile methods con entregas más frecuentes frente y por lo tanto con menor riesgo frente a Waterfall methods donde se hacen entregas que agrupan muchas más novedades y por lo tanto tienen mayor riesgo.

image

  • VS2012:
    • Backlog
    • My work en TFS
    • Testeo unitario “run after build”, Test manager y Testeo exploratorio.
    • Feedback manager
    • Detección de código duplicado.
    • DevOps
    • Web and load testing.

15:30 Caso de Estudio Transmediterránea Rido (Microsoft)

  • Migración de Mainframe de IBM (DB2, Ciqs, Cobol) a Azure (MSFT) (Windows Server (AppServer), Azure Platform as a Service, .Net).
  • Objetivo: ahorro costes de mantenimiento. La migración y mantenimiento de la nueva aplicación se paga en 5 años con la misma cuota mensual que se pagaba de mantenimiento por la original.
  • Se mantiene la capa transaccional (un 20% aprox. del código original) y se crea un interface que simula el original (consola).
    • En el punto de venta: “Pues si no ha cambiado nada!”
    • Equipo técnico: “De eso se trataba (objetivo cumplido)”
  • En una fase posterior se rediseñará la interfaz de usuario.
  • A destacar:
    • Impresoras desde Azure.
    • Tests, tests, tests…
    • Metodología KISS (Keep It Stupid & Simple)

16:00 Integre las Operaciones para una entrega continua (Kabel / Certia)

  • DevOps
  • SCOMLAB (Operations Manager)

16:30 Novedades en el Desarrollo Web & Cloud David Salgado (Microsoft)

Charla entretenida e interesante, de la que podemos encontrar un amplio resumen en el blog del ponente (http://dasalga.wordpress.com/2012/10/08/charla-de-web-cloud-en-vslaunch/). Habló de:

  • Novedades en VS2012 para desarrolladores Web:
  • HTML5, javascript, CSS
  • Movilidad
  • Comunicación
  • Cloud (Azure)
    • Plataforma virtualmente ilimitada
    • Autoservicio
    • Elástico
    • Pago por uso
  • Lo que se traduce en:
    • Economía
    • Agilidad
    • Foco
  • Diferentes opciones a la hora de exponer un desarrollo web al mercado móvil:
    • No hacer nada ^^ Si, así, con 2 narices. No hacemos nada… el usuario accede a nuestra web tradicional y se verá más o menos, además, como los navegadores móviles cada vez son mejores, pues hala. (En este escenario recomendamos al menos el uso de viewports)
    • Adaptative/Response UI. trabajar con media queries para que la interfaz se adapte a los tamaños de pantalla. Visita www.mediaqueri.es para hacerte una idea.
    • Un desarrollo móvil específico… donde utilicemos librerías como JQuery mobile  (incluida ahora en VS) para desarrollar el sitio.
  • Typescript
  • WebAPI
  • SignalR
  • Page inspector

17:30 Desarrollo para Dispositivos: nuevas experiencias de usuario (Icinetic)

  • Apps full-semantic (habilitar pinzado, etc)
  • Comportamiento diferenciado en horizontal y vertical.
  • Tecnologías: Azure, Web Services, MVC, HTML5
  • Blend para probar distintas configuraciones de pantalla.
  • Sensores
  • Demos

miércoles, septiembre 26, 2012

Modelo POCO a partir de ADO.NET Entity Data Model

Si decidimos utilizar Entity Framework para diseñar nuestro modelo de datos, tenemos la opción de utilizar el diseñador gráfico (siguiendo el patrón Database-First o Model-First dependiendo de si partimos de una base de datos existente o no), o crearlo “a pelo” (siguiendo el patrón Code-First). Para más info sobre estos patrones ver el post Database first vs Model first vs Code first.

Ambas formas de trabajar tienen sus gracias y sus inconvenientes:

La primera nos simplificará el trabajo de modelado de entidades y conexión con la base de datos, y además nos aporta una representación gráfica que siempre ayuda.

image

Para ello simplemente tenemos que añadir a nuestro proyecto un elemento de tipo ADO.NET Entity Data Model:

image

La segunda forma de trabajar (sin utilizar el diseñador gráfico que proporciona ADO.NET Entity Data Model) nos dará mayor libertad para crear nuestras entidades y basarnos por ejemplo en un modelo de objetos POCO.

imageimage

Una de las posibilidades más interesantes es partir del modelo gráfico de ADO.NET Entity Data Model y a partir de él generar las entidades POCO y el contexto de BDD. Esto se puede conseguir utilizando un generador de código desde el diseñador:

image

image

Como se ve existen multitud de plantillas entre las que elegir, y no es objetivo de este post explicar cada una de ellas. Para generar un modelo de objetos POCO nos pueden servir por ejemplo ADO.NET POCO Entity Generator y ADO.NET DbContext Generator.

ADO.NET Entity Data Model y Data Annotations

Data Annotations permite añadir validaciones al modelo de datos que luego tendrán reflejo en la vista. A continuación mostraré un ejemplo de aplicación hecha con ASP.NET con una única entidad (Team) definida en el modelo de datos y su controlador y vistas creadas por scaffolding (ver post Cómo crear un CRUD (mantenimiento) básico Web utilizando ASP.Net MVC y Entity Framework).

Supongamos que partimos de una entidad Team definida así:

using System.ComponentModel;
using System;
using System.Collections.Generic;  
namespace PruebaEF
{
    public partial class Team
    {
        public int Id { get; set; }        
        public string Name { get; set; }         
        public string City { get; set; }
    }
}

Si creamos el controlador y las vistas mediante scaffolding y ejecutamos el proyecto tendremos (ojo, tendremos que añadir /teams a la URL inicial).


image


image


Si modificamos la entidad añadiendo Data Annotations podemos conseguir algunas validaciones sin necesidad de modificar ni el controlador ni la vista. Veamos el siguiente ejemplo:



using System.ComponentModel;
using
System.ComponentModel.DataAnnotations;
using System;
using
System.Collections.Generic;

namespace
PruebaEF
{
   
   
public partial class Team
    {
        [DisplayName("Identificador")]
       
public int Id { get; set
; }

        [
DisplayName("Nombre del club"
)] 
        [
StringLength
(10)]
       
public string Name { get; set
; }


        [DisplayName("Ciudad")]
       
public string City { get; set
; }
    }
}


El resultado sería el siguiente (sin necesidad de modificar ni el controlador ni las vistas):


image


image


Pero si las entidades las generamos utilizando ADO.NET Entity Data Model tal como se explica en el post anterior (Modelo POCO a partir de ADO.NET Entity Data Model), cada vez que hagamos una modificación desde el diseñador, perderemos las Data Annotations. ¿Y qué podemos hacer al respecto? Tenemos varias opciones aunque ninguna me parece perfecta:



  1. Utilizar el patrón Database-First / Model-First para crear una primera versión del modelo de datos (tal como se explica en el post anterior (Modelo POCO a partir de ADO.NET Entity Data Model) y a partir de ahí eliminar el fichero edmx y pasar a utilizar el patrón Code-First. Siempre podríamos añadir después un elemento de tipo Diagrama de clase para tener una visión gráfica del modelo ;P
  2. Utilizar el generador de código (desde el diseñador) de ADO.NET POCO Entity Generator With Data Annotations. La pega es que sólo sirve para el patrón Database-First y no se pueden añadir o modificar validaciones en el modelo.
  3. Utilizar el patrón Code-First (ver Code-First Development with Entity Framework 4). Si partimos de una BDD existente, podemos utilizar Reverse Engineer Code First (ver Entity Framework Power Tools) para crear las entidades POCO a partir de los objetos de la BDD. Este sistema tampoco me convence porque crea unas clases para el mapeo mediante Fluent-API.
  4. Crear una clase a banda que contenga las anotaciones e indicarlo a la entidad original mediante el atributo MetadataType (ver Validation with the Data Annotation Validators).
  5. Desde el diseñador de ADO.NET Entity Data Model, como generador de código, utilizar ADO.NET Self-Tracking Entity Generator + Data Annotations, que permite añadir validaciones en el diseñador (propiedad Validations de cada una de las entidades). La pega es que esto no genera clases POCO (que es lo que yo estaba buscando).
  6. Utilizar Portable Extensible Metadata (ver Introducing the Portable Extensible Metadata), aunque con esto tampoco conseguiríamos tener clases POCO con anotaciones.

jueves, septiembre 13, 2012

Cómo consumir un Web Service desde PHP

A continuación un ejemplo sencillo en php que consume un Web Service en este caso de Navision (aunque eso es lo de menos):

<?php
define('USERPWD','192.168.0.150\Administrador:xxx'); // Sustituir xxx por la contraseña del servidor 
include("NTLMStream.php");  
include("NTLMSoapClient.php");
 
stream_wrapper_unregister('http');
stream_wrapper_register('http','NTLMStream'or die("Fallo al registrar protocolo");
$pageURL = 'http://192.168.0.150:7047/dynamicsnav/ws/Autoequip/Codeunit/NEUMALIAWS'; // El Web Service 
$params = array();
$params["param1"] = "2855519MDIAMARISVR"; // param1 es el nombre el primer parámetro.
$params["param2"] = "2";
$params["param3"] = "1024"; 
$client = new NTLMSoapClient($pageURL);
stream_wrapper_restore('http');
$result = $client->ImportPedNeumalia($params); // El método del Web Service 
$numped = $result->return_value;
echo 'Pedido creado: '.$numped;
die();
?>

 
Los módulos php incluídos son:

NTLMStream.php

<?php
class NTLMStream 
{ 
    private $path; 
    private $mode; 
    private $options; 
    private $opened_path; 
    private $buffer; 
    private $pos; 
    /** 
     * Open the stream 
      * 
     * @param unknown_type $path 
     * @param unknown_type $mode 
     * @param unknown_type $options 
     * @param unknown_type $opened_path 
     * @return unknown 
     */ 
    public function stream_open($path, $mode, $options, $opened_path) { 
        $this->path = $path; 
        $this->mode = $mode; 
        $this->options = $options; 
        $this->opened_path = $opened_path; 
        $this->createBuffer($path); 
        return true; 
    } 
    /** 
     * Close the stream 
     * 
     */ 
    public function stream_close() { 
        curl_close($this->ch); 
    } 
    /** 
     * Read the stream 
     * 
     * @param int $count number of bytes to read 
     * @return content from pos to count 
     */ 
    public function stream_read($count) { 
        if(strlen($this->buffer) == 0) { 
            return false; 
        } 
        $read = substr($this->buffer,$this->pos, $count); 
        $this->pos += $count; 
        return $read; 
    } 
    /** 
     * write the stream 
     * 
     * @param int $count number of bytes to read 
     * @return content from pos to count 
     */ 
    public function stream_write($data) { 
        if(strlen($this->buffer) == 0) { 
            return false; 
        } 
        return true; 
    } 
    /** 
     * 
     * @return true if eof else false 
     */ 
    public function stream_eof() { 
        return ($this->pos > strlen($this->buffer)); 
    } 
    /** 
     * @return int the position of the current read pointer 
     */ 
    public function stream_tell() { 
        return $this->pos; 
    } 
    /** 
     * Flush stream data 
     */ 
    public function stream_flush() { 
        $this->buffer = null; 
        $this->pos = null; 
    } 
    /** 
     * Stat the file, return only the size of the buffer 
     * 
     * @return array stat information 
     */ 
    public function stream_stat() { 
        $this->createBuffer($this->path); 
        $stat = array( 
            'size' => strlen($this->buffer), 
        ); 
        return $stat; 
    } 
    /** 
     * Stat the url, return only the size of the buffer 
     * 
     * @return array stat information 
     */ 
    public function url_stat($path, $flags) { 
        $this->createBuffer($path); 
        $stat = array( 
            'size' => strlen($this->buffer), 
        ); 
        return $stat; 
    } 
    /** 
     * Create the buffer by requesting the url through cURL 
     * 
     * @param unknown_type $path 
     */ 
    private function createBuffer($path) { 
        if($this->buffer) { 
            return; 
        } 
        $this->ch = curl_init($path); 
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true); 
        curl_setopt($this->ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 
        curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); 
        curl_setopt($this->ch, CURLOPT_USERPWD, USERPWD); 
        $this->buffer = curl_exec($this->ch); 
        $this->pos = 0; 
    } 
}
?>
 
NTLMSoapClient.php

<?php
class NTLMSoapClient extends SoapClient { 
    function __doRequest($request, $location, $action, $version) { 
        $headers = array( 
            'Method: POST', 
            'Connection: Keep-Alive', 
            'User-Agent: PHP-SOAP-CURL', 
            'Content-Type: text/xml; charset=utf-8', 
            'SOAPAction: "'.$action.'"', 
        ); 
        $this->__last_request_headers = $headers; 
        $ch = curl_init($location); 
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 
        curl_setopt($ch, CURLOPT_POST, true ); 
        curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 
        curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); 
        curl_setopt($ch, CURLOPT_USERPWD, USERPWD); 
        $response = curl_exec($ch); 
        return $response; 
    } 
 
    function __getLastRequestHeaders() { 
        return implode("\n", $this->__last_request_headers)."\n"; 
    } 
}
?> 
 
 
NOTA: Debemos asegurarnos que la extensión php_soap está habilitada; de lo contrario se producirá un error similar a este:
 
 

En el caso de tener WAMP como servidor de Apache/PHP/MySQL, esta opción la encontraremos dentro de las PHP_Extensions.