lunes, 30 de diciembre de 2013

WebSockets en MVC - Ejemplo práctico Horse Race

WebSockets es un protocolo de nueva generación que permite establecer comunicaciones bidireccionales sin la necesidad de abrir múltiples conexiones http en entornos web entre cliente y servidor. El objetivo del post no es explicar a fondo en que consiste este tipo de comunicación sino ver un ejemplo relativamente sencillo sobre como implementarlo en un entorno de desarrollo actual para hacernos una idea en que consiste.

Microsoft soporta este protocolo a nivel de servidor tanto en entornos ASP.NET WebForms como MVC. En nuestro caso nos centraremos en un entorno MVC, desarrollaremos paso a paso un ejemplo práctico de una carrera de caballos que se desplazarán horizontalmente sobre un canvas en una vista HTML5. Al ser algo relativamente reciente necesitaremos como mínimo una versión 2010 de Visual Studio y framework 4.0.

Veamos el ejemplo paso a paso:

Abrimos nuevos proyecto desde Visual Studio, creamos un proyecto MVC vacío desde Visual Studio (aquí estoy usando 2013 express)

Añadimos una carpeta "controllers", pulsamos botón derecho sobre la carpeta y en el menú contextual que se despliega seleccionamos "Agregar Controlador". En este punto veremos que el bueno de Visual Studio ha creado el resto de ficheros y carpetas necesarias para el site MVC automáticamente. Aprovechando la carpeta Content, crearía un subdirectorio Images donde ubicaré la imagen de los 2 caballos que compiten (negro y blanco).

Aquí tenemos nuestro controlador por defecto con el método Index.
namespace HorseRace.Controllers
{
    public class HorseRaceController : Controller
    {
        //
        // GET: /HorseRace/
        public ActionResult Index()
        {
            return View();
        }
    }
}
Si pulsamos botón derecho en el método Index el menú contextual nos permite añadir una vista para el método Index. Procedemos a crearla, en el menú asistente de creación de la vista dejamos los datos por defecto (no asociamos ningún modelo).

Si vamos bien hasta aquí tendremos una carpeta Views en el proyecto con una subcarpeta HorseRace y allí dentro se debería haber creado la vista Index.shtml.

En la vista añadiremos un elemento canvas, 2 imágenes ocultas y un apartado script. El canvas será el circuito de carreras donde veremos como avanzan los caballos. Se trataría de copiar este código en la vista HTML.

Index.shtml
<canvas height="100" id="myCanvas" style="border:1px solid #000000;background-color:#8BA870" width="560"></canvas>
<img src="~/Content/Images/caballonegro.png" style="visibility: hidden" id="caballo1" />
<img src="~/Content/Images/caballoblanco.png" style="visibility:hidden" id="caballo2" />
<script>
    var c = document.getElementById('myCanvas');
    var ctx = c.getContext('2d');
    var caballo2 = document.getElementById('caballo1');
    var caballo1 = document.getElementById('caballo2');
    var xC1 = 1;
    var yC1 = 4;
    var xC2 = 1;
    var yC2 = 54;
    initField();
    caballo1.addEventListener("load", drawHorseBlanco(xC1,yC1), false);
    caballo2.addEventListener("load", drawHorseNegro(xC2,yC2), false);
    

    function initField()
    {
        ctx.clearRect(0,0,c.width,c.height);
        ctx.strokeStyle = '#FFFFFF';
        ctx.moveTo(0, 50);
        ctx.lineTo(c.width, 50);
        ctx.stroke();
    }

    function drawHorseBlanco(x, y)
    {
        ctx.drawImage(caballo1, x, y);
    }

    function drawHorseNegro(x, y) {
        ctx.drawImage(caballo2, x, y);
    }
</script>
Hasta el momento tenemos el campo de carreras y los 2 caballos listos para competir, pero no hemos hecho prácticamente nada respecto a lo lógica de server ni hemos implementado todavía ningún aspecto de la comunicación WebSockets.

Llegado este punto ejecutaría el proyecto y veremos si todo está ok hasta aquí. En principio si indicamos la url http://[Host]/HorseRace/Index deberíamos visualizar algo como esto de la imagen.

WebSockets en MVC - Ejemplo práctico Horse Race


Dejamos por un rato el HTML-javascript de la parte cliente y vamos a definir la lógica de servidor en este caso tampoco me rompo los cuernos. Se trata de avanzar al azar la posición de los 2 caballos hasta que uno llega a la meta. Creamos una carpeta Business en el mismo proyecto y añadimos una clase Race.cs que se encargará de desplazar la coordenada X de ambos caballos de manera aleatoria hasta llegar a una posición limite. Es importante que el método InitHorseRace esté implementado de forma que puede ejecutarse de manera asíncrona.
namespace HorseRace.Business
{
    public class Race
    {
        public const int maxpositionX = 550;
        public List<int> mPosicionesCaballos = new List<int>() { 1, 1 };

        public Task InitHorseRace() 
        {
            return Task.Run(() =>
            {
                while (mPosicionesCaballos[0] < maxpositionX && mPosicionesCaballos[1] < maxpositionX)
                {
                    Thread.Sleep(50);
                    Movement();
                }
            }, new CancellationToken());

        }

        public void Movement() 
        {
            Random r = new Random();
            mPosicionesCaballos[0] += r.Next(1, 5);
            mPosicionesCaballos[1] += r.Next(1, 5);
        }

        public List<int> GetMovement() 
        {
            return mPosicionesCaballos;
        }
    }
}
Ahora ya sí vamos a crear la comunicación WebSockets entre cliente y servidor. Pulsamos botón derecho sobre la carpeta Controllers y añadimos un controlador en blanco. Hacemos que el controlador herede de ApiController, si partimos de un proyecto MVC vacío tendremos que añadir a global.asax el mappeo de la ruta.

namespace HorseRace.Controllers
{
  public class WsHorseRaceController : ApiController
  {
    //
    // Get: api/WsHorseRace/
    public HttpResponseMessage Get()
    {
      if (System.Web.HttpContext.Current.IsWebSocketRequest)
      {
        System.Web.HttpContext.Current.AcceptWebSocketRequest(ProcessWsRace);
      }
      return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
    }

    private async Task ProcessWsRace(AspNetWebSocketContext context)
    {  
      Task tRace;
      try
      {
        WebSocket socket = context.WebSocket;
        while (true)
        {
          ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]);
          WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
          if (socket.State == WebSocketState.Open)
          {
            string userMessage = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
            switch (userMessage)
            {
              case "init":
                Race BusinessHorseRace = new Race();
                tRace = BusinessHorseRace.InitHorseRace();
                while (!tRace.IsCompleted)
                {
                  Thread.Sleep(50);
                  List<int> positions = BusinessHorseRace.GetMovement();

                  buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(System.Web.Helpers.Json.Encode(positions)));
                  await socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
                }
               break;
            }
          }
          else
          {
            break;
          }
        }
      }
      catch (Exception ex) 
      {
        throw ex;
      }
  }
}
Mappeo de la ruta para ApiController.
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
En cliente (vista) añadiremos un botón que iniciará la conexión con el servidor... una vez iniciada el servidor irá enviando "comandos" para que cliente pueda mostrar como se van moviendo los caballos a medida que avance la carrera en servidor.
//añadir este botón debajo del canvas en index.shtml
<input type="button" id="btnConnect" value="Iniciar Carrera" />
//añadir este código js en la sección "script" de la vista index.shtml.
    var ws;
    $().ready(function () {
        $('#btnConnect').click(function () {
            ws = new WebSocket('ws://' + window.location.hostname + '/api/WsHorseRace');
            ws.onopen = function () {
                ws.send('init');
            };
            ws.onmessage = function (evt) {
                var positions = $.parseJSON(evt.data);
                initField();
                drawHorseBlanco(positions[0], yC1);
                drawHorseNegro(positions[1], yC2);
            };
            ws.onerror = function (evt) {
                alert(evt.message);
                ws.close();
            };
            ws.onclose = function () {
            };
        });
Ahora si pulsamos F5 ya deberíamos ver como los caballos al pulsar "Iniciar Carrera" se empiezan a mover por el eje X cada 50 milisegundos aleatoriamente entre 1 y 5 coordenadas. Tal y como está montada la lógica en servidor el que tenga más suerte con el random ganará la carrera.

WebSockets en MVC - Ejemplo práctico Horse Race

WebSockets en MVC - Ejemplo práctico Horse Race

En el ejemplo faltaría controlar cuando la carrera acaba, cerrar la conexión ws y mostrar una etiqueta en cliente mostrando el caballo ganador....

Consideraciones:
  • Este tipo de protocolo en servidor no está soportado por todas las versiones de IIS. Tened en cuenta que con la versión IIS Express de Visual Studio no funciona, tendréis que crearos el site en el servidor web local de la máquina.
  • La parte cliente también requiere una versión reciente del navegador, si alguien está planteándose implementar este tipo de comunicación en algún proyecto aseguraos a partir de que versión de cada navegador está soportado. Recomiendo echarle un ojo a SignalR.
  • En parte servidor para implementar el controlar que activa la conexión WebSocket usamos clases que pertenecen al ensamblado System.Net, System.Net.Http y System.Net.WebSockets. Depende que paquetes tengáis instalados o no en vuestro entorno es posible que tengáis que tirar de NuGet para obtener estos ensamblados.
  • La parte cliente necesita una referencia Jquery.
  • En el ejemplo hemos optado por implementar WebSockets en un proyecto MVC pero podríamos haberlo implementado también en ASP .NET tradicional.
  • Hemos optado en cliente por conectar al servicio usando código javacript pero también se podría crear un cliente con código .NET usando el mismo ensamblado System.Net.WebSockets.

Hasta aquí el artículo de hoy, el siguiente veremos el mismo caso práctico pero usando SignalR 2.0. Si alguien está interesado en que le envíe el código contactad conmigo vía linkedin o google. Como siempre cualquier comentario o debate es bienvenido y recordaros que podéis seguir areaTIC en las redes sociales!

lunes, 25 de noviembre de 2013

Hangouts vs Lync

Si estás pensando en utilizar algún software para la realización de videoconferencias seguramente te interesará este artículo donde comento algunos aspectos a tener en cuenta si las opciones son Google+ Hangouts o Lync.

Hangouts vs Lync

Lo normal sería que si te mueves en un ecosistema Microsoft (Active Directory, Office, Outlook...) la opción debería ser Lync mientras que si el ecosistema es Google (GMail, Google Docs, Google+...) lo normal es la opción de Hangouts; lo que sucede es que no siempre las cosas son tan claras y sencillas así que sería importante tener en cuenta los siguientes factores antes de tomar una decisión:
  • Si trabajamos en un entorno con Active Directory (en adelante AD), Lync se integra perfectamente con AD (es suficiente con el login en el equipo), Office y especialmente todas las funcionalidades de Outlook (libreta de direcciones, citas, salas,....). Hangouts no se integra con AD por lo que iniciar una videoconferencia con Hangouts requerirá mínimo 2 logins de usuario (si no lo tenemos almacenado).

  • Los usuarios de Lync pueden comunicarse con los otros usuarios, internamente o fuera de su organización, incluso si no tienen instalado Lync (por ejemplo,es compatible con Skype). Por el contrario, los usuarios de Hangouts sólo pueden comunicarse a través de vídeo con otros usuarios de Hangouts. De hecho, con Lync existen 4 opciones para conectar a una videoconferencia:

    1. Mediante Skype (sería gratuito)

    2. Mediante Lync web app (sería gratuito). No se pueden organizar reuniones (sólo los usuarios con licencias de pago pueden organizarlas) pero pueden asistir a reuniones, tener audio/vídeo... Podemos encontrar más información en el siguiente enlace.

    3. Mediante usuarios externos federados (se requiere de licencia) es la opción mediante la cual un propietario con N licencias disponibles puede asignar licencias a usuarios que no la tienen para realizar videoconferencias. Podemos encontrar más información en el siguiente enlace.

    4. Por supuesto disponer de licencias de Lync.

  • Lync es compatible con Citrix pero sobre Hangouts no hay información al respecto, ni de compatibilidad ni de incompatibilidad. Podemos encontrar más información sobre la compatibilidad de Lync con Citrix en el siguiente enlace.

  • En cuanto a ubicación y protección de los datos, en cuanto a Lync y si contratas en España, Microsoft garantiza que los datos se almacenan en un servidor ubicado en la UE y cumpliendo las disposiciones legales correspondientes. En cuanto a Hangouts, Google no garantiza la ubicación de los datos en la UE pero está suscrito al programa Safe Harbor garantizando también su protección. En cualquier caso, es importante tener en cuenta esta peculiaridad. En cuanto a la confidencialidad de Google, cuidado con este párrafo que podemos ver en las condiciones del servicio de Hangouts:

    Al utilizar el Servicio, otorgas a Google el derecho y la licencia para albergar, almacenar en caché, enrutar, transmitir, almacenar, copiar, modificar (en la medida de lo técnicamente necesario para facilitar y ejecutar el Servicio), emitir, exhibir y comunicar públicamente, mostrar, cambiar el formato, extraer, analizar, crear algoritmos derivados, utilizar o proporcionar el Contenido en directo (el cual puede incluir contenido facilitado tanto por ti como por los demás participantes del hangout, por ejemplo, grabaciones acústicas o composiciones) por alguna otra vía en todo el mundo. Por el presente documento, aceptas que esta licencia otorga a Google el derecho a facilitar el Contenido en directo a otras empresas, organizaciones o personas con quien Google se relacione para facilitar servicios sindicados, así como a utilizar dicho contenido en relación con el suministro de estos servicios. Por el presente acuerdo, confirmas y garantizas a Google que posees todos los derechos, poderes y autoridad necesarios para conceder esta licencia.
    

  • En cuanto a las características del producto en sí podríamos destacar:

    1. Lync permite reuniones en línea con un máximo de 250 participantes, Hangouts está limitado a sólo 15. Interesante dato aunque prefiero no pensar lo que puede ser una reunión en línea con 250 personas, je je je...

    2. Lync permite a los usuarios eliminar participantes. Por el contrario en Hangouts sólo se puede bloquear un participante, y sólo si todos los demás están de acuerdo.

    3. A diferencia de Lync, que se adapta automáticamente a las condiciones cambiantes del ancho de banda, Hangouts requiere que los usuarios se muevan un control deslizante de ancho de banda para mantener conversaciones en zonas con escasa conectividad.

    4. Lync, a diferencia de Hangouts, dispone de un Add-in de traducción de conversaciones.

    5. Tanto Lync como Hangouts permiten vídeo en Full HD, intercambio de ficheros y compartición de escritorio.

  • Mirando el tema de precios, Lync no está disponible de forma gratuita (tendríamos que usar Skype) y Hangouts sí. Si estamos dispuestos a pagar por el servicio (con sus correspondientes ventajas en cuanto a soporte,...) a día de hoy tendríamos, por cada usuario, que por 4€/mes podemos disponer de Gmail + Hangouts mientras que para el equivalente en Microsoft tendríamos un coste de unos 7,75€/mes (3,25€ de Exchange Online + 4,50€/mes de Lync).

  • Si queremos más información al respecto podemos encontrarla en los siguientes enlaces:

    1. Detalles sobre Lync
    2. Microsoft vs Google Apps (by Microsoft)
    3. Blog de Office 365
    4. Sitio de Google Hangouts

Hasta aquí el artículo de hoy, espero que os sea útil y nos contéis vuestras experiencias con una u otra herramienta; 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...).


miércoles, 30 de octubre de 2013

C#: Leer archivos adjuntos email con interops

El articulo de hoy expone un modo sencillo para leer los adjuntos de un correo de outlook usando la librería Microsoft.Office.Interop.Outlook en lenguaje C#. No sería un tema pionero ya que hay muchas librerías que permiten hacerlo desde hace tiempo pero aquí está por si alguien lo necesita.

En mi caso no consigo hacer que la gente suba la documentación a un aplicativo porque les llega por correo y pierden tiempo descargándolos fichero a fichero para posteriormente clasificarlos en la aplicación. La idea es proporcionarles una interfaz en el aplicativo de gestión que les permita seleccionar un correo, muestre todos sus adjuntos permitiendo seleccionar uno o varios y clasificarlos de manera rápida el mismo formulario.

Os paso el código:
public static class Lib 
{
   public static List<byte[]> LeerAdjuntosMail(string pMail) 
   {
    try
    {
     Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
     MailItem mail = app.CreateItemFromTemplate(pMail);
     List<byte[]> archivos = new List<byte[]>();

     foreach (Attachment adj in mail.Attachments) 
     {
       string filepath = string.Format(@"{0}\{1}", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), adj.DisplayName);
       adj.SaveAsFile(filepath);
       archivos.Add(FileToByte(filepath));
       System.IO.File.Delete(filepath);
     }
     return archivos;
     }
     catch (System.Exception ex)
     {
        throw ex;
     }
   }

   public static byte[] FileToByte(string sFullFileName)
   {
    try
    {
      byte[] bytes;
      // Declaramos fs para tener acceso al fichero residente en la maquina cliente.
      using (FileStream fs = new FileStream(sFullFileName, FileMode.Open))
      {
        using (BinaryReader br = new BinaryReader(fs))
        {
          bytes = new byte[(int)fs.Length];
          br.Read(bytes, 0, bytes.Length);
        }
      }
      return bytes;
      }
      catch (System.Exception ex)
      {
        throw ex;
      }
    }
}
El método LeerAdjuntosEmail espera como parámetro la ruta donde se ha descargado el email, de momento al ser una versión que no tengo claro que vayan a usar no perdemos demasiado tiempo en conectar a un buzón ni nada por el estilo si no que partimos del correo una vez descargado a disco para leer sus adjuntos (.msg).

Hasta aquí el artículo de hoy, podéis seguir areaTIC en las principales redes sociales, comentar y valorar todo lo que os apetezca y más. Hasta la semana que viene!

martes, 22 de octubre de 2013

Blogger: Formulario de contacto en una página

En el artículo Blogger: nuevos gadgets, seguidores de Google+, formulario de contacto y Wikipedia os comentaba la incorporación de 3 nuevos gadgets a Blogger. Bien, tras escribir el artículo me decidí a añadir el gadget Formulario de contacto en areaTIC.net, me puse manos a la obra pero digamos que la cosa no tenía buena pinta:

  • Al añadirlo como gadget, si no controlamos la visualización dependiendo de la URL, vemos que el formulario de contacto se nos repite en todas las entradas... mi idea era añadirlo en una página, no en las entradas. Buscamos en Google y rápidamente encontramos un blog dónde nos explican cómo añadir el gadget en una página estática.

  • Seguimos, el gadget formulario de contacto de Blogger sólo dispone de 3 campos y posiblemente nos gustaría añadir nuevos: una lista de selección, un check... no es posible, estas opciones no son configurables en el gadget formulario de contacto de Blogger.

  • Otro problema que me encuentro, el mail al que llega el formulario de contacto cuando es rellenado es aquel con el que entramos a Blogger y añadimos el gadget. No se puede cambiar ni añadir nuevos destinatarios del formulario de contacto de Blogger.

  • Para evitar que spambots puedan rellenar mi formulario de contacto e inundarme mi buzón de spam me gustaría que mi formulario de contacto tuviera un campo de tipo captcha y así asegurarme que quien lo rellena es una persona y no una máquina o servicio; con el gadget Formulario de contacto de Blogger esto no es posible.

Así que en este punto me planteo si vale la pena o no añadir un formulario de contacto en areaTIC.net... pero claro, los formularios de contacto mejoran la imagen de marca para los visitantes del blog, nos puede ayudar a mejorar las tasas de conversión,... hay que añadirlo. Buscando por aquí y por allá encuentro distintas herramientas para crear formularios: Kontactr, EmailMeForm, Foxyform, CloudContactForms... hay miles pero ninguna me convencía, básicamente porque las versiones gratuitas eran con funcionalidades bastante limitadas o incluían publicidad... y así hasta que dí con JotForm.


Nos registramos en un par de minutos y ya podemos acceder a la página principal donde vemos nuestros formularios y podemos crear nuevos. En la versión gratuita podemos crear formularios ilimitados, la restricción de espacio es de 100Mb, podemos tener 100 "submits" mensuales, 10 si son SSL y 10 recepciones de pago; para empezar es suficiente, la funcionalidades del formulario son las mismas en todas las versiones, las veremos más adelante.


Creamos (o editamos) un formulario, se muestra la siguiente pantalla donde tenemos las distintas opciones para personalizarlo. Os las detallo haciendo especial hincapié en aquellas que no podíamos hacer gadget formulario de contacto de Blogger.


  • Podemos añadir al formulario tantos campos como queramos, en la barra de menús de la izquierda tenemos diferentes tipos de campos: cajas de texto, desplegables, botones de radio, checks, posibilidad de subir ficheros, selectores, captchas, imágenes, campos para realizar pagos,... Pulsando sobre el menú superior "Estilo de forma" podemos elegir fuente, tamaño, alineación... y para los campos podemos indicar validaciones, subetiqueta, valor predeterminado, de solo lectura... vamos, que tenemos múltiples opciones de personalización. Por supuesto se puede modificar el texto del botón "Enviar".

  • Si pulsamos sobre el menú superior "Configuración e incrustación" encontraremos varias opciones, algunas de ellas muy interesantes:

    • La opción "Alertas de correo" nos permita generar notificaciones, cada una puede ser para un destinatario diferente y podemos personalizar el formato del mail que recibirá el destinatario.

    • La opción "Thank you" permite personalizar el mensaje que se muestra tras rellenar el formulario y pulsar el botón Enviar. Pocas herramientas permiten esto, normalmente es un mensaje estándar con publicidad de la herramienta utilizada para generar el formulario.

    • La opción "Insertar formulario" nos ofrece distintas opciones para añadir el formulario en nuestro sitio: iframe, embedido, popup,... así como instrucciones para añadirlo en diferentes plataformas como Wordpress, facebook, Drupal... Esto nos permite añadir nuestro formulario como un gadget, en una página estática,...

    • La opción "Condiciones" permite crear reglas sobre los campos del formulario, por ejemplo, que ciertos campos se oculten tras marcar un check o que según el valor escogido en un desplegable se envíe el mail a un destinatario u otro,...

  • En este punto tenemos todos los inconvenientes del gadget formulario de contacto de Blogger superados, todo ello a coste 0 (siempre que no hagamos un uso masivo), totalmente personalizable y sin ningún tipo de publicidad.

  • Otro punto que destacaría es el apartado "Form Templates" donde podemos encontrar más de 50 plantillas de formularios diferentes: contacto, evaluación, pago, reserva,...

Ya para acabar, en la sección CONTACTO de areaTIC.net podéis encontrar un formulario de contacto hecho con esta herramienta, sencillo, práctico y funcional. Hasta aquí el artículo de hoy, 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...).


miércoles, 16 de octubre de 2013

HTML, Javascript: Cómo obtener la posición absoluta de un elemento HTML

En un determinado momento nos podría interesar recuperar la posición x, y absoluta de un elemento HTML de nuestra página independientemente de cuántos elementos más hayan en la página. Esto podría sernos útil si estamos trabajando dentro un elemento canvas.

Por ejemplo, centrándonos en Canvas, si dibujamos un círculo tendríamos que indicarle la posición X, Y donde queremos que empiece.

x = 20;
y = 10;
radio = 10;
ctx.arc(x, y, radio, 0, 2 * Math.PI);

Esto dibujaría un círculo partiendo de la posición relativa que le hemos especificado dentro del canvas. Cuando hablamos de posición relativa quiere decir que los valores siempre son tomando como referencia la posición del Canvas. Es decir si el Canvas se visualiza en cliente en la posición x = 40 la posición absoluta donde empieza nuestra circunferencia sería 40 + 20.

Podríamos aplicar este código para determinar si se ha producido un click en un punto más a la derecha que nuestra circunferencia.

Eventoclick.x >= x + 40;

Dado este caso, suponiendo que tenemos el canvas en un nivel justo inferior al documento HTML lo único que nos influye son los márgenes de la página. Podemos recuperar sin problemas el valor donde se encuentra el canvas usando la propiedad offsetLeft (todos los elementos HTML tienen esta propiedad).

areaTIC: Cómo obtener la posición absoluta de un elemento HTML, figura 1
EventoClick.x >= x + canvas.offsetLeft;

Ahora supongamos un escenario que se ajusta más a la realidad donde el Canvas no está en la raíz del documento sino que tiene como “padre” un elemento Div que a su vez está situado a la derecha de otro elemento Div.

areaTIC: Cómo obtener la posición absoluta de un elemento HTML, figura 2

Es importante saber que la propiedad offsetLeft devolverá la posición relativa respecto al elemento HTML que lo contiene, por tanto el código anterior dejaría de funcionar. Para que vuelva a funcionar necesitaríamos calcular recursivamente e ir sumando los offsetLeft de cada uno de los elementos superiores al Canvas hasta llegar al elemento root.

Hasta aquí el ejemplillo. Os copio una función que he encontrado en stackoverflow para calcular posiciones absolutas que funciona a la perfección.
function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}
var x = getOffset( document.getElementById('yourElId') ).left; 
Hasta aquí el artículo de hoy, recordar como siempre que podéis areaTIC a través de las principales redes sociales y enviar vuestras valoraciones, comentarios, etc... que vaya bien la semana!

martes, 8 de octubre de 2013

SQL Server: 'TRUNCATE_ONLY' no es una opción BACKUP reconocida

Recientemente realizando unos tareas de mantenimiento en SQL Server 2008 me encontré con el error 'TRUNCATE_ONLY' no es una opción BACKUP reconocida. De entrada me extrañó porque de entrada todo era correcto y el script había utilizado anteriormente en SQL Server 2005 así que me puse a investigar; la secuencia de comandos utilizada era:

-- Truncamos registro de transacciones
USE[DatabaseName] BACKUP LOG [DatabaseName]WITH TRUNCATE_ONLY

-- Obtenemos error correspondiente
'TRUNCATE_ONLY' no es una opción BACKUP reconocida.

-- Debido al error anterior queda pendiente ejecutar la reducción del
-- registro de transaciones
-- USE [DatabaseName] DBCC SHRINKFILE ('DatabaseNameLog', 0)]

Lo primero, ir al MSDN a buscar información sobre el comando BACKUP en SQL Server 2008 donde nos encontramos el párrafo siguiente:

Las opciones BACKUP LOG WITH NO_LOG y WITH TRUNCATE_ONLY ya no se incluyen. Si usa el modelo de recuperación completa o el optimizado para cargas masivas de registros y debe quitar la cadena de copia de seguridad del registro de una base de datos, cambie al modelo de recuperación simple. Para obtener más información, vea Cambiar del modelo de recuperación completa al modelo de recuperación optimizado para cargas masivas de registros.

También en el artículo anterior podemos encontrar un enlace con información adicional sobre el truncamiento del registro de transacciones; básicamente (y simplificando) lo que nos viene a decir es que el truncamiento del registro de transacciones se produce automáticamente:

  • Después de un punto de control en el modelo de recuperación simple.

  • Tras una copia de seguridad del registro de transacciones en el modelo de recuperación completa si se cumplen ciertas condiciones (podéis verlas detalladas en el enlace anterior).

Buceando por distintos sitios parece desprenderse que la postura de Microsoft para eliminar la opción de BACKUP 'WITH TRUNCATE_ONLY' se debe al riesgo existente al forzar la eliminación de información del registro de transacciones. Según lo comentando anteriormente, y siguiendo las recomendaciones que Microsoft hace sobre el comando DBCC SHRINKFILE, si queremos reducir el tamaño del registro de transacciones podemos hacerlo cambiando el modelo de recuperación de la base de datos y luego restaurándolo:

-- Cambiamos modelo de recuperación a simple 
ALTER DATABASE [DatabaseName]
SET RECOVERY SIMPLE
GO
 
-- Reducimos tamaño del registro de transacciones
DBCC SHRINKFILE (DatabaseNameLog)
GO

-- Cambiamos modelo de recuperación a completa 
ALTER DATABASE [DatabaseName] 
SET RECOVERY FULL
GO

Habremos reducido el registro de transacciones y evitado el error 'TRUNCATE_ONLY' no es una opción BACKUP reconocida. Y hasta aquí el artículo de hoy, 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

martes, 1 de octubre de 2013

Blogger: nuevos gadgets, seguidores de Google+, formulario de contacto y Wikipedia

Recientemente Blogger ha incorporado a su lista de gadgets disponibles tres nuevos e interesantes gadgets que os describiré a continuación; además os indicaré paso a paso cómo podéis añadirlos a vuestro blog.

  1. Empezaremos hablando del gadget Seguidores de Google+, podéis encontrarlo en otras webs que lo denominan fanbox de Google+; básicamente es un gadget que muestra todos los contactos de nuestros círculos y que fácilmente permite a cualquier usuario añadirse. ¿De qué puede servir a nuestro blog los contactos? Podemos hacer que nuestros posts se añadan a Google+ y así todos nuestros contactos de Google+ tendrán fácil acceso a ellos sin necesidad de visitar nuestro blog, cuantos más contactos más posibilidad de atraer visitas a nuestro blog. El utilizar las redes sociales (Google+, LinkeIn, Facebook, Twitter,... para extender nuestros posts es una buena opción para conseguir aumentar las visitas de nuestro blog.

    En el artículo Seguidores en Facebook, Twitter, Google+ y LinkedIn os indicaba como añadir el fanbox de Google+, Facebook, Twitter y LinkedIn, todavía no existía el nuevo gadget Seguidores de Google+, os indico cómo añadirlo:

    • Entramos en Blogger, vamos a la sección 'Diseño' y pulsamos sobre 'Añadir un gadget'.


    • Dentro de la sección 'Lo básico' encontramos el nuevo gadget Seguidores de Google+, lo añadimos.


    • El siguiente paso es configurar el gadget Seguidores de Google+ indicando título, tamaño y gama de colores.
    • Guardamos la configuración del gadget Seguidores de Google+, la disposición en la sección 'Diseño' de nuestro blog y ya podemos ver el resultado.


  2. El siguiente nuevo gadget incorporado en Blogger es el gadget Formulario de contacto. Los formularios de contacto nos permiten recoger datos de nuestros visitantes (nombre, mail,...) y si los tratamos adecuadamente podemos convertir esos visitantes en futuros clientes. Por ejemplo, muchas webs te obligan a registrarte (Formulario de contacto) para descargarte una versión demo de un software... una vez descargado vas recibiendo mails de la web en cuestión con el objetivo que compres la versión completa del software; en resumen Formularios de contacto son una potente herramienta para convertir visitantes en clientes y de ahí que pueda ser interesante un gadget de este tipo en nuestro blog. Añadirlo es muy sencillo:

    • Como en el caso anterior, en la sección 'Diseño' pulsamos sobre 'Añadir un gadget'; en este caso vamos a la sección 'Más gadgets' donde veremos el nuevo gadget Formularios de Contacto.


    • Configuramos el gadget indicando el título.


    • Guardamos la configuración del gadget Formulario de contacto, la disposición en la sección 'Diseño' de nuestro blog y ya podemos ver el resultado. Los mensajes se recibirán en la cuenta de correo con la que accedes a tu blog.


  3. El último gadget incorporado en Blogger es el gadget Wikipedia que nos permite realizar búsquedas en la Wikipedia desde nuestro blog. El uso de este gadget puede resultar interesante para algunos blogs aunque todavía no le veo ningún aspecto que nos haga conseguir nuevas visitas o fidelizarlas, es más, cuando realizas una búsqueda y seleccionas uno de los resultados se abre una nueva ventana en el navegador y te muestra el contenido de la Wikipedia... este gadget lo que hace es aumentar el riesgo de fuga de nuestros visitantes. A pesar de eso os explicaré cómo añadirlo:

    • Como en el caso anterior, en la sección 'Diseño' pulsamos sobre 'Añadir un gadget'; en este caso vamos a la sección 'Más gadgets' donde veremos el nuevo gadget Wikipedia.


    • Configuramos el gadget indicando el título.


    • Guardamos la configuración del gadget Wikipedia, la disposición en la sección 'Diseño' de nuestro blog y ya podemos ver el resultado.


Y hasta aquí el artículo de hoy, si lo consideráis útil podéis añadir estos nuevos gadgets en vuestro blog. Recordad también 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...) 


miércoles, 25 de septiembre de 2013

Data Contract Serializer y maxOccurs="unbounded"

Hace unos días tuve un problema al actualizar un "Service Reference" a partir de un wsdl contra el que ya estábamos trabajando en producción pero necesitábamos ampliar algunas funcionalidades. El problema surgió al actualizar desde Visual Studio el proxy. En un principio no devolvió ningún error ni warning pero dejó de compilar el proyecto y empezó a fallar por todos lados... a priori el wsdl sólo se había modificado para añadir un nuevo método.

El error de compilación surge porque en el proxy (generado automáticamente) todas los objetos List<> han pasado a convertirse en array[], además se han añadido unos atributos

Specified

de tipo bool por cada propiedad pública que si no se les da valor true los datos no llegaban a servidor...

Tirando del hilo, veo que las clases se han generado a partir de XmlSerializer cuando hasta ahora estaba usando

Data Contract Serializer

que es serializador por defecto si usamos Service Reference de Visual Studio... Comparando directamente las diferencias entre los archivos del

wsdl

-

xsd

vimos que se había añadido una lista de string con el atributo

maxOccurs=unbounded

y que este atributo no es compatible con

Data Contract Serializer

tal y como estaba especificado en el fichero.

Soluciones:
  • La más sencilla y de estar por casa es eliminar el atributo manualmente del xsd, con esto ya funcionaría y podríamos salir del apuro.
  • La otra es ajustar el

    xsd

    como se explica a continuación para que

    Data Contract Serializer

    no de problemas

Fragmento xsd que da problemas con

Data Contract Serializer

:
<xs:complexType name="Response">
  <xs:sequence>
    <xs:element name="error" type="xs:boolean" />
    <xs:element name="errorMessage" nillable="true" type="xs:string" />
    <xs:element minOccurs="0" maxOccurs="unbounded" name="info" type="xs:string" />
  </xs:sequence>
</xs:complexType>
Fragmento xsd correcto:
<xs:complexType name="Response">
   <xs:sequence>
      <xs:element name="error" type="xs:boolean" />
      <xs:element name="errorMessage" nillable="true" type="xs:string" />
      <xs:element minOccurs="0" name="mensajes" nillable="true" type="tns:ArrayOfInfo" />
    </xs:sequence>
</xs:complexType>

<xs:complexType name="ArrayOfInfo">
   <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="info" nillable="true" type="xs:string" />
   </xs:sequence>
</xs:complexType>
Una vez optamos por una de estas 2 soluciones al actualizar servicio desde Visual Studio ya usa

Data Contract Serializer

de modo que nos hemos evitado tener que hacer refactoring de código y podemos seguir usando List<> que siempre es más cómodo que un array[].

Hasta aquí el artículo, espero que a alguien le sea útil. Recordar que podéis seguir

areaTIC

en las principales redes sociales, animaros a participar!

martes, 17 de septiembre de 2013

Turnapi: Documentar APIs en la nube

Llevo desde hace un tiempo trabajando en un proyecto entre varias empresas en el que una desarrolla una API con ciertas funcionalidades y otras consumen esta API desde sus aplicaciones. El caso es que, lógicamente, surgió la necesidad de documentar la API y tener esta documentación actualizada y accesible a todos los participantes... se pensó en Google Docs y otras soluciones similares pero finalmente optamos por Turnapi, os hago un breve resumen.

¿Qué es turnapi? Es una herramienta que nos permite de forma fácil e intuitiva documentar las APIs que desarrollemos. Dispone de control de versiones, es fácilmente configurable, podemos organizar la información, restringir el acceso a los usuarios que queramos, realizar búsquedas de forma global sobre toda la documentación... entre otras funcionalidades. La herramienta dispone de una versión gratuita 100% operativa aunque también dispone de versiones de pago que ofrece opciones como uso de nuestro dominio, SSL,... a través de este enlace podéis acceder a la lista de planes y precios de turnapi.

A continuación os comentaré los primeros pasos a dar en Turnapi y cómo llevar a cabo algunos aspectos de configuración:

  • Lo primero que debemos hacer es registrarnos, podemos hacerlo desde la home de la web de Turnapi indicando nombre, mail, contraseña y dominio (se creará un subdominio del tipo dominioespecficado.turnapi.com, por ejemplo, test.turnapi.com).


  • Una vez registrados en Turnapi accedemos a la página principal de la documentación de la API. Podemos configurar logo y menú de la cabecera, configurar el tree de la izquierda añadiendo nuevas entradas o modificar el contenido de la página que se nos visualiza (con título References). En la parte inferior de la pantalla hay disponible otro menú que nos permite cambiar el modo de visualización, seleccionar temas, acceso a la gestión de usuarios,...


  • Tal como comentaba en el apartado anterior,si en el menú inferior pulsamos sobre la opción 'Themes' podremos escoger el estilo para la documentación de nuestra API.


  • Si pulsamos sobre la opción 'Configure header' podremos cambiar el logo de la documentación de nuestra API, modificar los títulos de los menús existentes y añadir/elminar menús (de la barra superior horizontal).


  • En el cuadro de texto central escribiremos el contenido de la página pudiendo usar texto normal, tags html, listas, negrita, cursiva, imágenes,... y también añadir métodos (prefijo '#') y parámetros (prefijo '@param').


    La visualización de la página anterior sería la siguiente; en la parte inferior de la documentación nos saldrán links para exportarla a HTML, PDF o imprimir:


  • Pulsando sobre 'Configure tree' añadiremos nodos en el menú de la izquierda; dentro del mismo podemos crear submenús lo que nos permitirá organizar mejor la documentación de nuestra API.


  • En cualquier momento podemos grabar o grabar y publicar nuestra documentación. En cuanto grabemos se actualizarán las revisiones correspondientes (guardadas o guardas y publicadas y pulsando sobre 'history' veremos el historial de cambios.


  • Pulsando en la opción 'Settings' del menú inferior podremos indicar nombre y copyright para nuestro proyecto de documentación y lo que es más importante, hacer este proyecto privado; si lo marcamos supondrá que sólo podrá acceder a la documentación de la API aquellos usuarios que invitemos. MUY IMPORTANTE, por defecto los proyectos no son privados así que si no marcamos esta característica nuestra documentación será accesible a cualquier usuario de internet.


  • Si vamos a la opción 'Users' del menú inferior veremos la lista de usuarios del proyecto (aquellos que tienen acceso a la documentación si el proyecto es privado).


  • Podemos añadir usuarios pulsando el botón 'Invite Person' o eliminarlos pulsando sobre el link 'Remove' (y yo me pregunto, ¿por qué no habrán hecho 2 botones o 2 links?. Al invitar a una persona nos pide su mail y a este le llega el link de acceso y su contraseña (autogenerada), el login es su correo.


  • ... y cómo las características anteriores podría mostraros varias más. Podéis acceder al blog de la herramienta para ver otras características o acceder al libro de ruta para ver las últimas mejoras implementadas.

Hasta aquí el artículo de hoy, ¿qué os ha parecido? Si no os convence Turnapi como herramienta para generar la documentación de nuestras APIs existen otras herramientas similares como Apiary, Dojo... 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...).


miércoles, 11 de septiembre de 2013

SQL Server: Hint NOLOCK

En el artículo de hoy explicaremos el hint NOLOCK. Si recordáis el artículo SQL Server: Hint Maxdop os comentaba que existen tres tipos de hints, Join Hints, Query Hints y Table Hints; bien, el hint NOLOCK es del tipo Table (también conocidos como Lock Hints) por lo que se aplica en consultas de tipo SELECT, INSERT (sólo cuando contiene una cláusula SELECT), DELETE, UPDATE y MERGE, invalidando el comportamiento predeterminado del optimizador de consultas mientras dura la instrucción DML (Data Manipulation Language) especificando un tipo de bloqueo, uno o más índices,... Estos hints se especifican en la cláusula FROM de la instrucción mediante la cláusula WITH y sólo afectan a la tabla o vista a la que se hace referencia en esa cláusula. Podemos encontrar más información al respecto en el siguiente enlace del MSDN: Table Hints.

El hint NOLOCK es equivalente al READUNCOMITTED y básicamente lo que permite son 'dirty reads' (aunque también podrían producirse lecturas no repetibles y lecturas fantasma), lo podemos ver fácilmente con un ejemplo en el que utilizaremos la base de datos AdventureWorks:

  1. Abrimos una nueva consulta en SSMS y ejecutamos una sentencia SELECT:
    -- Buscamos todos los empleados solteros
    SELECT EmployeeID, LoginID, Title, MaritalStatus 
    FROM HumanResources.Employee 
    WHERE MaritalStatus = 'S'
    
    Obtenemos el siguiente resultado (podemos ver que el empleado con ID 2, Kevin, está soltero):


  2. Abrimos otra nueva consulta en SSMS y ejecutamos una sentencia UPDATE dentro de una transacción:
    -- Actualizamos el estado civil del empleado con ID 2
    BEGIN TRANSACTION
    UPDATE HumanResources.Employee
    SET MaritalStatus = 'M'
    WHERE EmployeeID = 2
    -- No finalizamos la transacción, podrá acabar con COMMIT o ROLLBACK
    
  3. Volvemos a lanzar la consulta del punto 1, ahora la consulta queda pendiente de ejecución ya que hay una transacción sobre los datos a los que se refiere.


    Esto es así porque el nivel de aislamiento (ISOLATION LEVEL) establecido es 'READ COMMITTED' (las instrucciones no pueden leer datos que hayan sido modificados pero no confirmados por otras transacciones); es el valor por defecto en SQL Server.

  4. Detenemos la consulta en ejecución del apartado anterior y modificamos la sentencia SELECT del punto 1 añadiendo el hint NOLOCK:
    -- Buscamos todos los empleados solteros
    SELECT EmployeeID, LoginID, Title, MaritalStatus 
    FROM HumanResources.Employee WITH (NOLOCK)
    WHERE MaritalStatus = 'S'
    
    Obtenemos el siguiente resultado (podemos ver que el empleado con ID 2, Kevin, no aparece, a pesar de no haber confirmado la transacción):


  5. Si ahora hiciéramos ROLLBACK en la sentencia UPDATE del paso 2 los resultados de la sentencia SELECT del paso 4 serían erróneos, tendríamos una 'lectura sucia' (dirty read) originada por el uso del hint NOLOCK.

Visto el uso del hint NOLOCK en el ejemplo anterior deberíamos tener en cuenta algunas consideraciones:
  • Lo primero que nos preguntaremos es, si el hint NOLOCK puede producir 'dirty reads', ¿para qué sirve? Como ya he comentado en algún otro artículo se debe ir con especial cuidado en el uso de hints, sea cual sea, ya que alteran la normal ejecución del optimizador de consultas y puede producir resultados no deseados. En el caso del hint NOLOCK y tomando de partida el ejemplo anterior se me ocurren 2 casos en los que puede sernos útil:

    • Supongamos que tenemos un nº de empleados mayor que 300, obtenemos los datos sobre el estado civil de los empleados (solteros, casados,...) y se muestra un gráfico de tipo pastel con los porcentajes de cada tipo. El estado civil no es algo que cambie frecuentemente, podemos lanzar la consulta SELECT con el hint NOLOCK y aunque los datos no sean 100% exactos el gráfico apenas se verá afectado.

    • Necesitamos un listado donde figure ID de empleado, nombre y estado civil; lanzando la consulta con el hint NOLOCK obtendremos el listado ignorando los posibles bloqueos de la tabla. Id, nombre del empleado y estado civil son datos que no deberían variar con frecuencia y algún dato no del todo correcto quizás no suponga un problema en este caso.

    Normalmente para la construcción de gráficos y extracción de listados es donde puede tener sentido (pero no siempre) el uso del hint NOLOCK. Se debe ir con especial cuidado en NO utilizar el hint NOLOCK en una sentencia SELECT si luego con los datos obtenidos se realizan INSERTs / UPDATEs / DELETEs ya que podemos estar generando datos corruptos.

  • En uno de los puntos anteriores comentaba que la consulta quedaba en ejecución porque el nivel de aislamiento era 'READ COMMITTED'; si queremos saber el nivel de aislamiento de la conexión que estamos usando debemos ejecutar la consulta:
    -- Obtención nivel de aislamiento
    DBCC useroptions
    
    Obtendremos el siguiente resultado (podemos ver que el nivel de aislamiento es 'READ COMMITED'):


  • El uso del hint NOLOCK sólo está permitido en las sentencias de tipo SELECT. Si lo añadimos a sentencias de tipo INSERT, DELETE o UPDATE obtendremos el error correspondiente, veamos un ejemplo:
    -- Actualizamos estado civil del empleado usando el hint NOLOCK
    UPDATE HumanResources.Employee WITH (NOLOCK)
    SET MaritalStatus = 'M'
    WHERE EmployeeID = 2
    
    Al ejecutar la consulta anterior obtendremos el siguiente mensaje de error:
    Mens. 1018, Nivel 15, Estado 1, Línea 1
    Sintaxis incorrecta cerca de 'NOLOCK'. Si se va a usar como parte de una sugerencia de tabla, es necesario escribir una palabra clave WITH y paréntesis. Vea los Libros en pantalla de SQL Server para conocer la sintaxis correcta.
    

  • Cuando usamos el hint NOLOCK en una sentencia SELECT se produce sobre la tabla en cuestión un bloqueo en modo Sch-S (bloqueo de estabilidad del esquema); por tanto, si dentro de una transacción se modifica la estructura de la tabla y lanzamos una sentencia SELECT con el hint NOLOCK sin que haya finalizado la transacción la consulta SELECT se quedará en espera. Veamos un ejemplo:
    -- Modificamos estructura de la tabla
    BEGIN TRANSACTION
    ALTER TABLE HumanResources.Employee 
    ADD Columna_Test VARCHAR(20) NULL ;
    -- La transacción podrá acabar con COMMIT o ROLLBACK
    
    -- En otra consulta lanzamos el SELECT, quedará en ejecución 
    -- hasta que finalice la transacción de la consulta anterior
    SELECT EmployeeID, LoginID, Title, MaritalStatus 
    FROM HumanResources.Employee WITH (NOLOCK)
    WHERE MaritalStatus = 'S'
    

  • Tampoco deberíamos confundir el hint NOLOCK con los hints READPAST o NOWAIT. Probablemente en un próximo artículo explique estos dos últimos y las diferencias entre los tres.

  • Si queremos aplicar el hint NOLOCK a una consulta con varias tablas o a varias consultas SELECT consecutivas deberíamos hacerlo de la siguiente manera, modificando el nivel de aislamiento:
    -- Cambiamos nivel de aislamiento para permitir lecturas
    -- no confirmadas
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    
    SELECT *
    FROM Table1
    INNER JOIN Table2 ON Table1.c1 = Table2.c2
    
    SELECT *
    FROM Table3
    
    -- Restauramos el nivel de aislamiento anterior
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    

Hasta aquí el artículo de hoy, 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

martes, 3 de septiembre de 2013

BI: Herramientas comerciales

Tras el artículo BI: Herramientas open source publicado el pasado mes de agosto llega el momento de realizar un breve análisis de las herramientas comerciales de BI más populares (al menos en mi entorno). Como siempre cuando realizamos análisis de herramientas, del tipo que sea, es conveniente consultar si existe lo que dice el cuadrante mágico de Gartner al respecto, en él podréis ver las fortalezas y debilidades de cada una de las herramientas analizadas.

  • Sobre Qliqview no comentaré mucho ya que el pasado mes de abril dediqué un artículo completo a la herramienta tras asistir a un workshop organizado por Qlitech Ibérica. Podéis acceder a través de este enlace al dicho artículo sobre Qlikview.


  • De IBM Cognos podríamos decir que es el líder del mercado. Nos ofrece utilidades para creación de procesos ETL, cuadros de mando, informes, espacio de trabajo unificado y herramientas de colaboración entre usuarios, uso en dispositivos móviles, integración con aplicaciones,... Existen tres versiones disponibles de IBM Cognos, Insight, Express y Enterprise, en el siguiente enlace podéis ver una comparativa entre ellas. También es posible acceder, previo registro podéis acceder a un video demostrativo de IBM Cognos. La familia de software Cognos dispone también de otras herramientas que completan y añaden funcionalidad al BI:

    • Cognos TM1: planificación, elaboración de presupuestos, informes, análisis y modelado bajo demanda.

    • Cognos FSR: elaboración de informes automatizada y marcado XBRL para reducir el riesgo y mejorar la eficiencia.

    • Cognos Controller: consolidación financiera completa, fiable y auditable.


  • MicroStrategy es otra herramienta de BI que además de las típicas funcionalidades de ETL, cuadros de mando, informes, uso en dispositivos móviles... destaca por su facilidad de uso y características sociales (facilidad para compartir datos con nuestros amigos y serguidores). Podéis acceder a una demo online previo registro con la particularidad que es posible cargar nuestros propios datos a partir de un excel, csv,... y también está disponible en modalidad SaaS. A través de este enlace podéis acceder a información detallada sobre MicroStrategy.


  • Si os habéis fijado con detalle en el cuadrante mágico de Gartner donde se analizan herramientas de BI habréis observado que aparece Microsoft... ¿dispone de una herramienta de BI? Como tal no pero ofrece las funcionalidades de BI mediante tres herramientas:

    • Microsoft Office, especialmente a través de Excel y disponible en modalidad SaaS mediante Office 365.

    • SQL Server, que ofrece almacenamiento de datos, ETL (mediante SSIS), análisis de datos (mediante SSAS), informes (mediante SSRS)... podríamos dedicar un artículo entero al BI en SQL Server. Por supuesto también está disponible en modalidad SaaS a través de Windows Azure (SQL Azure).

    • Sharepoint, ofreciendo todo lo relacionado con gestión documental y las características sociales tras al incorporación de Yammer a la plataforma.


  • Tableau Software es otra herramienta de BI con las típicas funcionalidades de ETL, análisis, cuadros de mando, informes, adaptada al uso en dispositivos móviles... previo registro podemos acceder una demo online; en el mismo sitio y sin necesidad de registrarnos podemos bajar una versión de escritorio o servidor de evaluación. Además, también dispone de la posibilidad de suscribirse a documentos (que se reciben por email y se puede trabajar sobre ellos) y capacidades sociales obteniendo y vinculando datos de facebook, twitter,... Disponible en modalidad SaaS el precio está en torno a los 500$ usuario/año; podemos acceder a través de este enlace a la lista completa de precios.


  • Si trabajamos en entornos Oracle o SAP por supuesto hay que tener en cuenta sus herramientas de BI, Oracle Enterprise Performance Management and Business Intelligence y SAP BUSINESS INTELLIGENCE; en los respectivos enlaces podéis encontrar más información, da para escribir varios artículos.

    También podría mencionar otras como Alteryx, SAS, Panorama Software,... quizás haga un segundo artículo entrando algo más en detalle de algunas de estas herramientas.

  • Y para finalizar, no olvidemos tampoco aquellas herramientas open source de BI que comentábamos en el artículo anterior y que disponen de una versión comercial: Pentaho, Jedox y Jaspersoft.

Hasta aquí el artículo de hoy, ¿utilizáis alguna herramienta comercial de BI que no haya mencionado o disponéis de información adicional sobre alguna de las comentadas? No dudéis en compartirlo con nuestros lectores a través de los comentarios, seguro que lo agradecerán... Recordad también 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...).


martes, 27 de agosto de 2013

Importancia DateTimeKind en escenarios de intercambio XML II

Hace un tiempo en

areaTIC

publicamos un articulo sobre un caso curioso al intercambiar

XML

mediante

soap

contra otro servidor (java) desde .NET.

Hasta ese momento sólo había tenido problemas con el tipo DateTime? (nullable), pero hoy revisando unos temas he visto que hay más casos donde hay que ir con cuidado y especificar bien la zona horaria para evitar problemas.

Veamos otro ejemplo diferente al nullable:
DateTime fechaDesde = new DateTime(2013, 08, 27, 15, 0, 0);
DateTime fechaHasta = DateTime.Now;
Al serializar estos valores el resultado es el siguiente (son las 17:15):
<fechaDesde>2013-08-27T15:00:00</fechaDesde>
<fechaHasta>2013-08-27T17:15:00.6152148+02:00</fechaHasta>
Yo me encuentro en la zona Central Europea (BCN) por eso concatena un +2:00 correspondiente a la zona horaria en la fecha Hasta, pero en la fecha desde no especifica zona horaria por lo que si no está controlado en servidor seguramente recibirá el valor "17:00" (Utc) en vez de "15:00" como quería enviar.

En cambio si definimos la fechaDesde de este modo ya estaríamos especificando el formato ok y el servidor lo procesará bien.
DateTime fechaDesde = new DateTime(2013, 08, 27, 15, 0, 0,DateTimeKind.Local);
DateTime fechaHasta = DateTime.Now;
Al serializar estos valores el resultado es el siguiente (son las 17:15):
<fechaDesde>2013-08-27T15:00:00+02:00</fechaDesde>
<fechaHasta>2013-08-27T17:15:00.6152148+02:00</fechaHasta>
A la inversa también estaba teniendo problemas, es decir asumía que toda petición que me llegaba vía

soap/xml

me venía en formato "Local" con lo que estaba provocando un desfase importante al notificar esa fecha. Por ejemplo suponeros el caso que una tercera parte involucrada espera esa fecha que recibes en un fichero de texto con formato "yyyy/MM/dd" y yo recibo "19/08/2013 23:00 Z" (donde z es equivalente a Utc o no especificar zona horaria). En este caso notificaríamos como fecha "2013/08/19". Si el servidor me hubiese notificado la fecha en formato "local" hubiese recibido como valor "20/08/2013 00:00 +02:00" y por tanto la fecha a notificar al tercero difiere de un día.

Conclusión, es importante pactar el valor de zona horaria que cada parte va a utilizar y en caso que no sea posible tenemos que obligarnos a que cada vez que recibamos una fecha por este sistema de intercambio controlar el formato y convertirlo en caso que sea necesario. A continuación un ejemplo (se debería controlar más formatos pero es por hacernos una idea):
if (fecha.Kind == DateTimeKind.Utc)
    fecha = TimeZoneInfo.ConvertTimeFromUtc(fecha,TimeZoneInfo.Local);
Hasta aquí el artículo de hoy, recordar que podéis seguir

areaTIC

en las redes sociales. Esperamos tu participación!