jueves, 26 de febrero de 2015

Right-to-Left

En un proyecto reciente hemos tenido el requerimiento de tener que soportar la orientación del texto de derecha a izquierda, y como intuyo que no será la última aplicación en la que tengamos que dar soporte a rtl, dejaré aquí algunas recetas y reflexiones que he ido acumulando durante el desarrollo de tan “exótica” feature.

Lo primero, como en todo, es entender que tenemos que hacer. Aunque suene de perogrullo, cambiar algo tan arraigado en nuestra cabeza como es el sentido de la escritura, puede suponer un esfuerzo de concentración extra para no perder ningún detalle. De hecho, no son pocas las veces que he llamado al cliente para que él mismo corroborara si algo tan simple como un texto o un imagen era acorde a rtl.

Al comienzo, gran parte del trabajo sucio lo hará el atributo dir de HTML. Este atributo nos permite especificar la orientación del texto de un elemento (ltr – por defecto – o rtl). Lo más sencillo es establecerlo en el body (sólo especificándolo de nuevo en los elementos en los que queramos sobrescribir el valor heredado, si es que tenemos esa necesidad). Además de dir como atributo, tenemos direction como propiedad CSS que cumple la misma función.

Por ejemplo el siguiente documento HTML se vería así si el valor de dir fuera rtl.

<body dir="rtl">

    <p>Hola mundo</p>

    <table>

        <tr>

            <td>Primera celda</td>

            <td>Segunda celda</td>

        </tr>

    </table>

</body>

image

Otro punto a tener en cuenta es la propiedad CSS float. Donde dije digo, digo Diego. Es decir, en rtl tendremos que flotar en el sentido opuesto al valor original. En el siguiente ejemplo (y aunque dir valga rtl) los divs seguirán flotante a la izquierda.

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Document</title>

    <style>

        div {

            margin-right: 10px;

            float: left;

        }

    </style>

</head>

<body dir="rtl">

    <div>Div 1</div>

    <div>Div 2</div>

</body>

</html>

Para solucionarlo (así al menos lo he hecho yo), lo que hago es volver a definir la regla CSS (mismo selector pero definido después del original, así prevalecerá) y sobreescribir las propiedades que son necesarias. Digo “necesarias” en plural porque no sólo tenemos que preocuparnos por float, sino también de todas aquellas propiedades que hayamos utilizado en alguno de ambos lados del elemento (léase margin-left, margin-right, padding-left, etc.). Dicho esto, style quedaría así:

<style>

    div {

        margin-right: 10px;

        float: left;

    }

 

    div {

        margin-right: 0;

        margin-left: 10px;

        float: right;

    }

</style>

Si en algún momento la cascada de CSS nos jugara una mala pasada, siempre podemos hacer una regla con una especificad mayor que la original (aunque lo más sencillo es incluir todas estas reglas en un fichero rtl.css y asegurarse de que lo cargamos después de los estilos originales). Por ejemplo:

body[dir="rtl"] div {

    margin-right: 0;

    margin-left: 10px;

    float: right;

}

Además de float, el posicionamiento absoluto, relativo o fijo también tocará revisarlo. Si la idea era anclar algo en la esquina superior derecha (por ejemplo una x para cerrar), ahora deberemos hacerlo en la esquina superior izquierda, luego pasaremos de utilizar la propiedad left a utilizar la propiedad right.

    <style>

        .close-button {

            right: 0;

            top: 0;

        }

 

        .close-button {

            left: 0;

            right: auto;

        }

    </style>

Ya en Javascript, aunque está bien eso de separar contenido, estilo y comportamiento, me ha pasado que en algunos plugins de jQuery estaba dando estilo directamente a través de código. En este caso y para aplicar un estilo u otro en función de dir podríamos utilizar esta función:

    <script>

        function isRtl() {

            return document.body.dir === "rtl";

        }

    </script>

Algo que también tenemos que vigilar es la orientación de las imágenes. Por ejemplo, si tenemos una imagen con una flecha apuntando a la izquierda para indicar que se abrirá un panel en esa dirección, si ahora el panel se abre en la dirección opuesta lógicamente la flecha tendrá que estar apuntado en la dirección adecuada.

En este y otros muchos casos y para intentar no volverme muy loco, he creado un par de métodos de extensión para facilitar la tarea:

using System.Threading;

using System.Web;

using System.Web.Mvc;

using Antlr.Runtime.Misc;

 

namespace WebApplication1

{

    public enum Direction

    {

        Left,

        Right

    }

 

    public static class HtmlLanguageExtensions

    {

        public static HtmlString Dir(this HtmlHelper that)

        {

            return new HtmlString(!IsRtl() ? "ltr" : "rtl");

        }

 

        public static HtmlString Direction(

            this HtmlHelper that,

            Func<string> left,

            Func<string> right)

        {

            return new HtmlString(!IsRtl() ? left() : right());

        }

 

        public static HtmlString Direction(

            this HtmlHelper that,

            Direction direction)

        {

            string retval;

            if (!IsRtl())

            {

                retval =

                    direction == WebApplication1.Direction.Left ?

                    "left" :

                    "right";

            }

            else

            {

                retval =

                    direction == WebApplication1.Direction.Left ?

                    "right" :

                    "left";

            }

            return new HtmlString(retval);

        }

 

        public static HtmlString Lang(this HtmlHelper that)

        {

            return new HtmlString(Culture.GetCurrentTwoLetterISOLanguageName());

        }

 

        private static bool IsRtl()

        {

            return Thread.CurrentThread.CurrentUICulture.TextInfo.IsRightToLeft;

        }

    }

}

Ahora en vez de escribir esto:

<img src="~/Content/images/flecha-izquierda.svg" />

Escribiría esto otro:

<img src="~/Content/images/flecha-@(Html.Direction(() => "izquierda", () => "derecha")).svg" />

Y en el caso de que los literales a devolver fueran directamente “left” o “right”, escribiría esto:

<img src="~/Content/images/arrow-@(Html.Direction(Direction.Left).svg" />

Por último, estamos utilizando Bootstrap como framework CSS y de serie no soporta rtl. Si utilizamos por ejemplo la regla .list-inline veríamos esto:

image

Algo raro está pasando… esa scrollbar…, el estilo de .list-inline es:

.list-inline {

  padding-left: 0;

  margin-left: -5px;

  list-style: none;

}

.list-inline > li {

  display: inline-block;

  padding-right: 5px;

  padding-left: 5px;

}

Gracias a que siempre hay algún buen samaritano con un repo en github (desde aquí le quiero dar gracias al autor) la solución pasa por incluir una segunda hola de estilos que de soporte a rtl en Bootstrap. El repo es https://github.com/morteza/bootstrap-rtl. Para utilzar esta nueva hoja de estilos tenemos que agregar el enlace después de haber cargado Boostrap.

<link rel="stylesheet" href="//cdn.rawgit.com/morteza/bootstrap-rtl/master/dist/cdnjs/3.3.1/css/bootstrap-rtl.min.css">

Ahora el estilo de .list-inline pasará a ser:

.list-inline {

    padding-right: 0;

    padding-left: initial;

    margin-right: -5px;

    margin-left: 0;

}

Y ya entonces si tenemos una lista de Bootstrap funcionando correctamente con rtl

image

La verdad es que no he comprobado si todos los componentes y estilos de Boostrap son soportados en rtl con esta nuevo hoja de estilos, pero aquí voy a optar por ser reactivo y según vaya encontrándome problemas iré buscando soluciones.

Hasta aquí mi aventura con rtl, espero te sirva de ayuda!

Un saludo!

domingo, 9 de noviembre de 2014

IIS Express con Sublime Text y Brackets

Intentando salir de la zona de confort una de las probables vías a explorar es cambiar de IDE. Lo cierto es que Visual Studio es un magnifico IDE y además nos presta todo tipo de ayudas y comodidades para ni pensar tener que abandonarlo, pero claro, si queremos hacer cosas distintas tendremos que probar herramientas distintas.

Algunas de las opciones a valorar como nuevo IDE podrían ser Sublime Text o Brackets (también y seguramente como opción más confiable sería WebStorm, pero es de pago y prefiero por ahora no abordarlo).

Para ambos editores (llamarlos IDE o editores de texto lo dejo a tu elección) he echado en falta la existencia de un servidor local para trabajar desde http:// en vez de desde file:///. Lógicamente en VS eso no es problema porque cuando creamos un proyecto web se crea un nuevo sitio web en IIS Express para albergar nuestra aplicación. ¿Y por qué no utilizar entonces IIS Express también para Sublime Text o Brackets? Lo cierto es que un servidor ligero, de fácil instalación a través de Web Platform Installer y además que ya conocemos…o casi… porque su principal problema es su administración o, mejor dicho, la inexistencia de una herramienta gráfica para administrarlo. Es cierto que hay intentos de dotar a IIS Express de interfaz gráfica, pero con franqueza, ninguno parece estar completamente operativo, algunos ejemplos son https://iisexpressgui.codeplex.com/ o http://iisem.codeplex.com/

En este punto lo única opción viable parece administrar IIS Express desde línea de comandos con la utilidad appcmd.exe. Para equipos de 64 bits podremos encontrarla en C:\Program Files (x86)\IIS Express.

Con appcmd podremos realizar las operaciones de administración más comunes como listar, crear, modificar o eliminar sitios, aplicaciones o directorios virtuales. En nuestro caso nos centraremos en administrar sitios, que es lo que crea VS en IIS Express cuando creamos un proyecto web.

image

La configuración de IIS Express se guarda en el fichero %USERPROFILE%\Documents\IISExpress\config\applicationhost.config, aquí y dentro de la sección sites, encontraemos tantos elementos site como sitios tengamos configurados.

Un site luce más o menos así:

        <site id="1" name="WebApplication1">

            <application applicationpool="Clr4IntegratedAppPool" path="/">

                <virtualdirectory path="/" physicalpath="C:\Users\Sergio\Visual Studio 2013\Projects\WebApplication1\WebApplication1">

                </virtualdirectory>

            </application>

            <bindings>

                <binding bindinginformation="*:65534:localhost" protocol="http">

                </binding>

            </bindings>
        </site>

Para listar todos los sitios configurados ejecutaremos el comando appcmd list site

Para crear un nuevo sitio que apunte a C:\Temp podemos ejecutar el comando
appcmd add site /name:"Temp Site" /bindings:http/*:65533:locahost /physicalPath:"C:\Temp"

El puerto podría ser cualquiera mayor que el 1024, puedes ver esta y otras limitaciones en Running IIS Express without Administrative Privileges.

Para arrancar ahora nuestro nuevo sitio ejecutar el comando
iisexpress /site:"Temp Site"

En este punto la consola quedará suspendido mostrando un traza de las peticiones entrantes, para detener el sitio bien podemos pulsar “q” en la consola, o detenerlo desde el icono del área de notificaciones de Windows que agrega IIS Express.

IIS Express también permite levantar un sitio directamente desde una ubicación en disco con el comando iisexpress /path:”C:\Temp”. Esto levantará el servidor en el puerto por defecto 8080, pero lógicamente podríamos haber especificado el puerto también en el comando. Aquí puedes ver toda la documentación de iisexpress. Lo importante de este último comando es que no ha sido necesario registrar previamente en la configuración el sitio, con lo que levantarlo ha sido muy rápido y directo.

Ahora que ya tenemos un servidor web sirviendo contenido de una carpeta en disco ¿Cómo encaja todo esto con Sublime Text y Brackets?

Con Brackets es muy sencillo, simplemente File > Project Settings… y allí especificar la dirección de “Live Preview Base URL”, en nuestro caso http://localhost:8080/

Cabe mencionar que utilizando nuestro propio servidor en Brackets, algunas características del Live Preview no estarán disponibles… en realidad la experiencia del Live Preview merma bastante, puedes encontrar toda la información en https://github.com/adobe/brackets/wiki/How-to-Use-Brackets en el apartado Live Preview > Using your own backend.

Con Sublime Text primero hay que instalar el paquete SideBarEnhancements (paquete must-have) que agrega al menú contextual de una carpeta abierta en Sublime un buen puñado de opciones, entre las cuales está Project > Edit Preview URLs… Al pulsar en esta opción nos abrirá un fichero vacío llamado SideBarEnhancements.json (que se guardará %APPDATA%\Sublime Text 3\Settings) donde escribiremos lo siguiente:

{

    "C:\Temp": {

        "url_testing":"http://localhost:8080/",

        "url_production":""

    }
}

Ahora al pulsar la opción “Open In Browser” en el menú contextual del fichero en el Side Bar (ojo que no funcionará si pulsamos “Open In Browser” en el menú contextual desde el editor del fichero), nos abrirá el navegador predeterminado en la url especificada en url_testing. Más información de esta característica en https://github.com/titoBouzout/SideBarEnhancements

Después de todo esto, la sensación que tengo es que abandonar VS va a ser difícil :)

Un saludo!

domingo, 26 de octubre de 2014

OutputCache con MvcDonutCaching y MongoDB

Si hablamos de cache en una aplicación ASP.NET MVC, una de las primeras opciones a valorar es utilizar el atributo OutputCache para cachear la salida de los controladores.

Aunque a priori OutputCache podría satisfacer nuestros requerimientos, lo cierto es que adolece de algunos problemas que hacen que uso no sea todo lo satisfactorio que cabría esperar.

Muchos de estos problemas están relacionados con el uso del atributo en acciones hijas (las que son invocadas con Html.Action). En concreto, encontramos las siguientes limitaciones cuando hablamos de acciones hijas:

  • Sólo soportan las propiedades Duration, VarByCustom y VarByParam. Lo más relevante aquí es que no soporta la propiedad CacheProfile y, por ende, no podemos establecer una política de expiración de caché a través del web.config.
  • Ignora por completo el valor del atributo enableOutputCache de la sección outputCache del web.config. Esto significa que algo tan habitual como jugar con este valor para activar o desactivar la cache en desarrollo, no funcionará con acciones hijas.

En cualquier caso, no sólo las acciones hijas presentan limitaciones. Si pensamos en qué querríamos cachear en el contexto de la salida de ASP.NET MVC, encontraríamos fácilmente los siguientes escenarios:

  • Cachear la página entera (Full page caching). Soportado puesto que cachear una acción padre engloba cachear todo el resultado del método de acción.
  • Cachear pequeños fragmentos de la página (también llamado cachear el agujero del donut, Donut hole caching). Igualmente soportado a través de la cache de acciones hijas.
  • Cachear la página entera excepto pequeños fragmentos (lo que se llama cachear el donut pero no el agujero, Donut caching). Esto NO está soportado por el proveedor de serie aun cuando, si recordamos, se podía hacer por ejemplo en WebForms a través del control Substitution.

Otro problema grave que nos encontramos es que invalidar la cache no es algo que esté muy conseguido. Sólo tenemos disponible un triste método Response.RemoveOutputCacheItem(path) que sólo funciona para acciones padre y además no permite invalidar de una sola vez todas las versiones de una página, es decir, tendremos que llamar a este método tantas veces como distintas versiones de path haya que incluyan parámetros como segmentos en el path.

El cómo solventar todos estos problemas de un plumazo es sencillo, utilizando el paquete MvcDonutCaching

Este paquete nos brinda un nuevo atributo llamado DonutOutputCache, que sustituye por completo a OutputCache y hace que todo funcione como debería funcionar. Ahora no hay distinción entre acciones padres e hijas, todo funciona (las acciones hijas ya pueden utilizar CacheProfile, están al tanto de enableOutputCache, etc.) y además nos permite cachear el donut (Donut caching). En este sentido, MvcDonutCaching lo pone muy fácil porque agrega sobrecargas al helper Html.Action para poder especificar si la llamada a la acción hija debe excluirse de la cache de su padre, por ejemplo en vez de escribir @Html.Action(“Acción”), si escribimos @Html.Action(“Accion”, true) ya estaríamos cacheando el donut.

MvcDonutCaching además también permite invalidar la caché de forma precisa con los métodos RemoveItem y RemoveItems de la clase OutputCacheManager.

En este punto ya somos más felices, pero si cabe (y si es necesario) podríamos serlo un poco más. Esto es debido a que a partir de .NET 4.0 se introdujo la posibilidad de crear nuestro propio proveedor de cache personalizado y configurarlo vía web.config. Siendo así podemos hacer que nuestra cache persista en un almacenamiento compartido permitiendo que varios frontales compartan la misma cache e incluso que la cache sobreviva a reinicios de la aplicación. En mi caso he optado por crear un proveedor de cache basado en MongoDB.

Para ello hay que crear una clase que herede de OutputCacheProvider, implemente los métodos necesarios y configurar el nuevo proveedor vía web.config.

El código del proveedor está disponible en github https://github.com/panicoenlaxbox/MvcDonutCaching.MongoDBOutputCache y también hay disponible paquete de Nuget para instalarlo de forma sencilla http://www.nuget.org/packages/MvcDonutCaching.MongoDBOutputCache/

Resumiendo, los pasos para configurar el cache como hemos explicado son:

1. Instalar el paquete MvcDonutCaching

2. Instalar el paquete MvcDonutCaching.MongoDBOutputCache

3. Configurar el proveedor en el web.config

    <caching>

      <outputCache defaultProvider="AspNetMongoDB">

        <providers>

          <add name="AspNetMongoDB" type="MongoDBOutputCache.MongoDBOutputCacheProvider, MongoDBOutputCache" />

        </providers>

      </outputCache>

    </caching>

4. Agregar las siguientes claves en AppSettings (lógicamente apuntando a la instancia de MongoDB que quieras utilizar – con o sin autenticación – y especificando la base de datos que quieres utilizar):

    <add key="MongoDBOutputCacheProviderConnectionString" value="mongodb://admin:admin@localhost/aspnet" />

    <add key="MongoDBOutputCacheProviderCollection" value="OutputCache" />

Y ahora sí, tenemos una cache de salida de ASP.NET MVC como hubiésemos querido en un principio!

Un saludo!

jueves, 16 de octubre de 2014

Conversiones de usuario en C#

Las conversiones de usuario permiten definir conversiones personalizadas en C#, tanto explícitas como implícitas, desde un tipo origen a un tipo destino.

Lo cierto es que no suelo utilizarlas mucho (por no decir rara y extrañísima vez), pero como siempre estamos buscando una oportunidad para poner en juego características del lenguaje, recientemente me he encontrado con un caso que he resuelto con una conversión de usuario.

Para poner en situación, primero veremos un ejemplo de cómo son y qué hacen.
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var age = 38;
            Person person = age; // implícita de int a Person
            Console.WriteLine(person.Age); // 38 
            age = (int)person; // explícita, necesario cast, de Person a int            
            Console.WriteLine(age); // 38
            Console.ReadKey();
        }
    }

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }

        public static implicit operator Person(int age)
        {
            return new Person() { Age = age };
        }

        public static explicit operator int(Person person)
        {
            return person.Age;
        }
    }
}
Como se puede ver en el ejemplo, la sintaxis de una conversión de usuario es:
public static {implicit|explicit} operator TipoDestino (TipoOrigen identificador) 
{
 // do something…
return TipoDestino;
}
Las restricciones que se aplican a una conversión de usuario son:

  • Sólo son válidas para clases y estructuras.
  • TipoDestino y TipoOrigen tienen que ser de distinto tipo.
  • No puede haber una relación de herencia entre TipoDestino y TipoOrigen
  • TipoDestino y TipoOrigen no pueden ser de un tipo interface ni object.
  • No se puede declarar la misma conversión tanto de forma implícita como explícita
  • No se puede usar el operador is
  • No se puede usar el operador as

Después de la teoría y ya sabiendo que es una conversión de usuario, el ejemplo donde he aplicado una conversión de usuario es en un método que devuelve si se puede o no enviar un pedido. El problema está en que si no se puede enviar el pedido, querría saber también el motivo. Es decir, el siguiente código no me servía.
    public class Order
    {
        public string CustomerId { get; set; }
        public DateTime? DeliveryDate { get; set; }

        public bool CanBeSent()
        {
            if (string.IsNullOrEmpty(CustomerId))
            {
                return false;
            }
            if (DeliveryDate == null)
            {
                return false;
            }
            return true;
        }
    }
Para solucionar el problema expuesto y haciendo uso de las conversiones de usuario, podemos hacer que el método devuelve un tipo complejo indicando si es o no posible enviar el pedido y, en caso negativo, también especificar el motivo. Además, el valor devuelto se puede trabajar tanto como un booleano como un tipo complejo cuando sea necesario.
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var order = new Order();
            var result = order.CanBeSent();
            if (result)
            {
                Console.WriteLine("Se puede enviar el pedido");
            }
            else
            {
                Console.WriteLine("No se puede enviar el pedido");
                Console.WriteLine(result.Reason);
            }
            Console.ReadKey();
        }
    }

    public class CanBeResult
    {
        public bool Value { get; set; }
        public string Reason { get; set; }

        public CanBeResult(bool value)
        {
            Value = value;
        }

        public CanBeResult(bool value, string reason)
            : this(value)
        {
            Reason = reason;
        }

        public static implicit operator bool(CanBeResult result)
        {
            return result.Value;
        }

        public static implicit operator CanBeResult(bool value)
        {
            return new CanBeResult(value);
        }
    }

    public class Order
    {
        public string CustomerId { get; set; }
        public DateTime? DeliveryDate { get; set; }

        public CanBeResult CanBeSent()
        {
            if (string.IsNullOrEmpty(CustomerId))
            {
                return new CanBeResult(false, "El pedido no tiene cliente");
            }
            if (DeliveryDate == null)
            {
                return new CanBeResult(false, "El pedido no tiene fecha de entrega");
            }
            return true;
        }
    }
}
Un saludo!

lunes, 29 de septiembre de 2014

Configuración de seguridad en MongoDB

Después de aceptar MongoDB como animal de compañía y ver como configurarlo a nivel Newbie, quedó pendiente algo tan básico y necesario como establecer unos ciertos mínimos de seguridad para que nuestra instancia de Mongo no sea un “pasen y vean”.

En mi opinión (y después de ver las distintas opciones de configuración disponibles) he agregado los siguientes parámetros al fichero de configuración.
Básicamente activamos la autenticación de usuarios, sólo permitimos conexiones desde la ip local (ya que en nuestro caso tanto IIS como Mongo están en el mismo servidor), cambiamos el puerto por defecto (para no dar pistas) y deshabilitamos cualquier acceso vía http tanto a la parte de administración como a la API Rest. De este modo el fichero .config final quedaría de la siguiente forma (basado en formato YAML).
storage: dbPath: C:\mongodb\data\db systemLog: destination: file path: C:\mongodb\log\mongodb.log logAppend: true security: authorization: "enabled" net: bindIp: "127.0.0.1" port: XXXXX #27017 http: enabled: false RESTInterfaceEnabled: false
Algunas de estas opciones tienen valores predeterminados que ya coinciden con lo aquí expuesto, pero prefiero ser explícito y así olvidarme de ello.

Después de esto y para una bd de ejemplo llamada aspnet, sólo restar comentar como agregar usuarios y activar la autenticación.

Los pasos a seguir serían:
  • Crear usuario admin con el role “root” en la bd admin
  • Crear usuario aspnet con el role “dwOwner” en la bd aspnet
  • Modificar el fichero .config con la configuración propuesta
  • Reiniciar el servicio de Mongo
> use admin switched to db admin > db.createUser({user: "admin", pwd: "1234", roles: ["root"]}) Successfully added user: { "user" : "admin", "roles" : [ "root" ] } > use aspnet switched to db aspnet > db.createUser({user: "aspnet", pwd: "1234", roles: ["dbOwner"]}) Successfully added user: { "user" : "aspnet", "roles" : [ "dbOwner" ] } >
Lógicamente el nombre de usuario podría ser cualquiera (yo he utilizado admin y aspnet que coinciden con los nombres de las bases de datos sólo por sencillez).

Finalmente, para conectar vía C# tenemos que utilizar una cadena de conexión que incluye la autenticación y base de datos por defecto.

Asumiendo que la cadena de conexión debería cumplir mongodb://usuario:contraseña@host:puerto/bd, en nuestro ejemplo quedaría como mongodb://aspnet:1234@localhost:XXXXX/aspnet
Y recuerda (porque me ha pasado), que si incluyes el caracter @ en el nombre de usuario o contraseña, tendrás que escaparlo con %40.

Un saludo!

lunes, 18 de agosto de 2014

Configurar MongoDB nivel Newbie

En nuestro último proyecto hemos apostado por MongoDB para persistir los datos de un proveedor personalizado de TempData en ASP.NET MVC.

Lo cierto es que instalar MongoDB no es complicado, pero cada vez que hay que hay instalarlo y configurarlo en un equipo nuevo en la oficina, se invierte un tiempo valioso en volver a leer la documentación y ponerlo en línea. Es por ello que en este post veremos como ponerlo en funcionamiento siguiendo unos sencillos pasos.

Una vez descargado e instalado lo siguiente será configurarlo.

Yo personalmente sólo configuro lo siguiente:

  • Ruta a las bases de datos.
  • Creación de un fichero de log.
  • Instalación como un servicio.

Aunque podemos arrancar desde la línea de comandos mongod.exe con los parámetros --dbpath y --logpath, parece más útil crear un fichero de configuración donde establecer estos valores y algún otro.

La sintaxis del fichero de configuración puede ser YAML (a partir de la versión 2.6) o estilo INI (versiones anteriores pero todavía soportado en las versión actual por compatibilidad).

Si eliges YAML ten en cuenta que no le gustan los tabuladores y que espera encontrar espacios.

El fichero de configuración en YAML sería como sigue:

storage:

  dbPath: C:\MongoDB\data\db #Por defecto C:\data\db

systemLog:

  destination: file

  path: C:\MongoDB\log\mongo.log

  logAppend: true

En formato INI sería así:

dbpath = C:\MongoDB\data\db

logpath = C:\MongoDB\log\mongodb.log

logappend = true

En ambos ficheros de configuración se está configurando:

  • La ruta a las bases de datos
  • La ruta al fichero de log
  • Se está especificando que el fichero de log no sea eliminado cada vez que mongod arranque de nuevo.

Como podrás imaginar hay un montón de configuración extra que puede especificarse, bien desde la línea de comandos bien desde un fichero de configuración. Cabe mencionar también que todos los directorios que referenciemos en nuestro fichero de configuración tienen que estar creados. Es decir, mongod no creará ningún directorio por nosotros.

Sea cual sea el formato elegido, ahora podremos arrancar nuestra instancia de mongod con el siguiente comando:

mongod --config ruta_fichero_configuración

En nuestro caso, el fichero de configuración lo guardamos en C:\MongoDB\config.conf.

En este punto ya podríamos arrancar MongoDB desde la línea de comandos, pero para ponerlo aun más sencillo (y porque en un servidor de producción no parece adecuado), veremos ahora como crear un servicio que arranque MongoDB automáticamente. La verdad es que es muy sencillo y mongod viene ya preparado para que la tarea sea coser y cantar.

Lo único que hay que hacer es abrir un cmd con permisos de administrador y escribir lo siguiente:

mongod --config "C:\MongoDB\config.conf" --install

Y ya está, MongoDB instalado como un servicio!

Lo último que tienes que hacer es arrancar el servicio y ejecutar mongo.exe desde la línea de comandos o utilizar un cliente gráfico como Robomongo (gracias @_rubenfa) o MongoVUE.

Un saludo!