Hace unos meses que empecé una nueva andadura profesional, que me ha tenido bastante ocupado, por lo que no he tenido tiempo de actualizar el blog con nuevo contenido, hasta ahora.

Últimamente, dedico mi tiempo profesional a trabajar con Sitecore, que es un CMS desarrollado en .Net, enfocado a grandes webs corporativas con grandes volúmenes de contenido y requisitos de personalización. Este CMS, a pesar de su complejidad, tiene un rendimiento notable, gracias a varios niveles de caché incorporados, que funcionan bastante bien.

Sin embargo, Sitecore permite añadir nuestro propio código, y, en este caso, obtener el mejor rendimiento nos corresponde a nosotros. Para ayudarnos en esta tarea, estoy utilizando MiniProfiler, que es un plugin para monitorizar aplicaciones web desarrolladas en .NET, muy útil para analizar el rendimiento de nuestras páginas en “tiempo real”, sin la necesidad de indagar a posteriori en el log de Sitecore, o utilizar las herramientas de profiling que también nos ofrece. Además, está disponible como código abierto en GitHub: https://github.com/MiniProfiler

Lo que a priori parecía una tarea sencilla, “Instalar MiniProfiler en Sitecore”, terminó necesitando cierto tiempo de investigación (aún me queda mucho Sitecore que aprender…), por lo que reproduzco a continuación los pasos necesarios para activar MiniProfiler en una instancia de Sitecore, en mi caso, la versión 6.6, aunque entiendo que será muy similar para cualquier versión posterior.

Instalar MiniProfiler en Sitecore

El primer paso, obvio, consiste en instalar MiniProfiler en nuestro proyecto. Para ello, la manera más sencilla es utilizar NuGet.

  1. Abrir la ventana de comandos de NuGet.
  2. Seleccionar en el desplegable de “Proyecto por defecto” el proyecto que contiene la aplicación web
  3. Ejecutar el comando: PM> Install-Package MiniProfiler

En este caso, estamos instalando la versión básica de MiniProfiler, suficiente para trabajar con ASP.NET WebForms. Podéis consultar en la web de MiniProfiler otras extensiones para MVC, EF, etc.

Configuración de MiniProfiler

A partir del proyecto de ejemplo para WebForms, podemos configurar fácilmente nuestra aplicación web.

Global.asax.cs:

  1. Añadir la configuración al archivo Global.asax.cs, que copiaremos de https://github.com/MiniProfiler/dotnet/blob/master/Sample.WebForms/Global.asax.cs
  2. En el método, recomiendo añadir las siguientes entradas a la lista de extensiones ignoradas por MiniProfiler, de manera que no apaezcan archivos estáticos ni las propias páginas de Sitecore:

Web.Config:

  1. Comprobar que la sección <Modules> tiene el atributo runAllManagedModulesForAllRequests=”true”.
  2. Añadir a la lista de URLs ignoradas por Sitecore la siguiente: /mini-profiler-resources, sin eliminar las de Sitecore.
  3. Por último, nos queda añadir a nuestro(s) layout(s) el código que incluye los archivos JS necesarios para mostrar los resultados en pantalla, justo antes de la etiqueta </body>:

A partir de este momento, publicamos los cambios en el site y ya debe de aparecernos la capa de timing que nos aporta MiniProfiler en la parte superior izquierda de nuestra web.

gracias (cc) Foto por woodleywonderworks

Aprovechando la reciente traducción de este sitio web al inglés, voy a dedicar este post a explicar cómo gestionar la traducción de contenidos en ASP.NET MVC multi idioma, cuando hablamos de contenido con cierto tamaño y formato, es decir, más allá de los archivos de recursos, útiles sobre todo para palabras o frases cortas.

Traducción mediante archivos de recursos

En mi caso, al iniciar la traducción, empecé utilizando archivos de Recursos (.resx), que permiten disponer de una librería de recursos organizados por clave-valor, en este caso, cadenas, donde es el propio servidor el que gestiona qué idioma mostrar.

Para ello, se dispone de un archivo “Content.resx” donde se definen todos los textos que vamos a utilizar, con su clave correspondiente:

resources1

A continuación, creamos un archivo con el mismo nombre, pero añadiéndole el sufijo del código ISO del idioma al que queremos traducir, que en el caso del inglés es “en”. Por tanto, el archivo será “Content.en.resx”, y duplicamos las claves del archivo original, pero traduciendo el contenido en este caso:

resources2

La aplicación utiliza los valores de:

para determinar el idioma a utilizar, y para ello utilizará el sufijo que hemos añadido al archivo de recursos. En caso de no encontrar ningún archivo con el sufijo correcto (“de”, por ejemplo), utilizará el archivo sin sufijo como fallback. Por eso este archivo sin sufijo siempre representa el idioma por defecto de nuestro contenido.

Las ventajas de este sistema es que al estar los recursos dentro del ensamblado, el acceso a los mismos es inmediato y es el sistema el que se encarga de decidir qué archivo de recursos utilizar en función del idioma, liberándonos de dicha tarea.

En nuestro ejemplo, ya podemos utilizar en la vista el siguiente código (si Content.resx está en el raíz de la aplicación):

que mostrará el subtítulo “Formación académica” en la tercera pestaña de la página “/es/about“, mientras que mostrará “Academic” en la página “/en/about“. En este caso, utilizo un parámetro en cada ruta “{culture}/about” que indica el idioma a seleccionar.

El código de ejemplo que gestiona el cambio de idioma sería:

Que implica que hemos definido en nuestra tabla de rutas que éstas tienen un parámetro {culture} en cada una de ellas. La gestión de rutas multi idioma la dejaremos para otra publicación.

Pero utilizar archivos de recursos tiene dos problemas fundamentales:

  • Al ser archivos compilados, es necesario volver a compilar y publicar las DLLs del site para cualquier modificación, lo que le resta versatilidad y mantenimiento.
  • Cuando necesitamos traducir grandes bloques de contenido, que a su vez incorporan formato HTML, se convierte en un formato poco manejable y que mezcla formato con contenido. Como ejemplo, si accedemos a una página con descripción de proyecto, como /es/Projects/web-personal, observamos que las secciones de “Descripción del proyecto” o “Responsabilidades y tareas” contienen gran cantidad de texto y formato.

Markdown al rescate

Para solucionarlo he separado el contenido en archivos de Markdown para editar el contenido. La sintaxis de Markdown es muy sencilla, y se hizo muy popular para la edición de Wikis, por ejemplo. Existen diversos editores para modificar archivos markdown, si no queremos tener que aprender la sintaxis. Yo estoy utilizando Markdown Pad 2.

Para diferenciar los idiomas, sigo utilizando la misma filosofía de sufijos ISO que con los archivos de recursos, añadiendo “.en” a los archivos en inglés. De esta manera, por ejemplo, para traducir el contenido de la sección “Responsabilidades y tareas” del ejemplo anterior, /es/Projects/web-personal, tenemos 2 archivos: Project12-tasks.md y Project12-tasks.en.md. De esta manera, la gestión del contenido se hace con un editor especializado, que me permite modificar el formato de manera sencilla, y los cambios son visibles con tan sólo subir el archivo afectado, sin tener que recompilar el site.

La edición de un archivo de markup es tan sencilla como abrir el archivo con el editor y realizar las modificaciones al contenido:

project12_tasks

Como se puede observar, el propio archivo de markdown permite incluir códigos HTML, aunque luego no los muestre en la vista previa. Esto es importante porque nos permite total flexibilidad con nuestro contenido y luego veremos como este código HTML insertado sí que es tenido en cuenta a la hora de generar el HTML asociado.

A modo de ejemplo, así es como ha quedado organizado el contenido asociado con el proyecto 12 completo, /es/Projects/web-personal:

project_md

Donde observamos un archivo de recursos para los textos sencillos, y dos archivos de markdown para las dos secciones complejas, y en cada caso, la correspondiente réplica en inglés.

De markdown a HTML

Obviamante, el formato markdown no se puede mostrar directamente en el navegador como tal, sino que tenemos que transformarlo al HTML correspondiente y enviarlo a la vista.

Para ello, utilizo la librería de código abierto MarkdowDeep, que nos permite transformar el contenido markdown en HTML con muy poco esfuerzo. También implementa una librería de cliente que nos permitiría editar el markdown desde el navegador, mediante javascript.

Para instalar la librería, utilizaremos Nuget. Existen dos versiones de la librería: una que sólo incluye la parte de .NET y otra que incluye además el código de cliente. En mi caso, sólo he necesitado la versión de .NET, por lo que procedemos a su instalación, desde la Consola de Nuget:

O a través del gestor de paquetes de Nuget:

markdowndeep

Una vez instalada, la manera más sencilla de utilizar es creándonos una extensión de HtmlHelper que gestione esta tarea:

Notas a destacar:

  • La función recibe como parámetro el nombre base del archivo a generar, por ejemplo “/Texts/Projects/Project12/Project12-desc”, y ella ya se encarga de añadirle el sufijo de idioma correspondiente y la extensión “.md”
  • Si no encuentra el archivo con la extensión del idioma seleccionado, utiliza como fallback el archivo por defecto sin idioma.
  • La lectura del archivo se puede almacenar en Caché, si queremos aligerar la carga de proceso, aunque según mis pruebas, y al ser archivos relativamente pequeños, la mejora es muy poca, del orden de 2ms por archivo.
  • Al instanciar la librería de Markdown con la propiedad MarkdownInHtml = true, permite que el HTML incluido en el archivo se incorpore también a la salida.
  • Finalmente, devolvemos el resultado de la generación con Raw() para que el HTML no se interprete como texto, sino como salida tal cual.
  • La línea de código:

obtiene el idioma seleccionado, en mi caso, de la ruta. Esta línea dependerá de la implementación del idioma de cada uno.

Una vez tenemos la extensión implementada, tan sólo nos queda utilizarla en nuestra vista:

Como nota adicional, he tenido problemas si la ruta del archivo no es un literal de texto, sino una cadena dinámica. En este caso, en lugar de utilizar la extensión, he tenido que utilizar directamente la clase estática para acceder al método:

Conclusiones

La combinación de archivos de recursos para textos cortos y sencillos, con archivos de texto para contenido más elaborados y con formato (en este caso mediante Markdown) nos permiten realizar una gestión sencilla de aplicaciones multi idioma, fácilmente ampliables a nuevos idiomas en un futuro y que facilitan la actualización de los contenidos en un futuro.

Seguramente hay otras soluciones y cada uno tiene sus trucos, pero esta es la que he utilizado yo en mi propia web. ¿Y tú, cómo gestionas grandes bloques de contenido multi idioma? ¡Se aceptan sugerencias!

dominio personalizado (cc) Foto por mistergwilson

En el anterior post sobre la instalación de WordPress en Windows Azure, veíamos como la URL que se generaba para nuestro sitio web era del estilo http://<mi-nombre>.azurewebsites.net. En este artículo vamos a ver cómo modificar la URL para que la web responda a un dominio personalizado propio como http://www.mi-nombre.com, por ejemplo.

Aclaración previa

Antes que nada, hay que hacer una aclaración sobre el funcionamiento de un sitio web en Azure:

Los sitios web gratuitos no permiten la personalización del nombre del dominio

En Azure existen 3 tipos de sitios web:

  1. Gratuito: con pocos recursos, ideal para hacer las pruebas de nuestra página sin coste, dispone de cuotas de uso que bloquean el acceso a la página si se superan..
  2. Compartido: recursos compartidos con otros sitios web, igualmente utiliza cuotas de uso, algo mayores que el modo Gratuito.
  3. Estándar: máquina virtual dedicada donde alojar tantos sitios web como queramos, o soporte el tamaño de la instancia.

Tan sólo los sitios web en modo Compartido o Estándar permiten la personalización del dominio.

Por ello, lo primero que tenemos que hacer es cambiar la web a uno de estos dos modos antes de configurar los dominios. Mi recomendación es hacerlo justo antes de lanzar la web al público final, o si el dominio real ya es necesario tenerlo para usarlo con otros servicios. De esta manera, ahorraremos costes hasta el momento del lanzamiento.

Para ello, accedemos al portal de gestión y entramos en la ficha del site que vamos a modificar. En este caso, he seleccionado el modo Compartido, más económico.

Azure-Shared

Configurando las DNS del dominio

Lo primero que necesitamos es configurar las DNS de nuestro dominio personalizado para que apunten a nuestro website en Azure. Para ello, tenemos que acceder al panel de administración de nuestro proveedor donde registramos el dominio y añadir el siguiente registro CNAME (o alias):

CNAME: <dominio-personalizado> -> http://<mi-nombre>.azurewebsites.net

En mi caso, y siguiendo con el ejemplo anterior, he creado un registro CNAME para mi-nuevo-wordpress.sergigisbert.com que apunta a mi-nuevo-wordpress.azurewebsites.net.

Dominio personalizado

Configurando el site con el nuevo dominio

Una vez tenemos redirigido el dominio y hemos cambiado el modo de proceso del site, accedemos al panel de administración y comprobamos cómo se ha habilitado la funcionalidad de “Administrar dominio”, que en el modo gratuito está deshabilitada. El botón se encuentra en la barra inferior:

Azure-AdminDomains

En la ventana que se nos abre, introducimos el dominio personalizar que previamente hemos redirigido con el alias DNS:

Azure-NewDomain

Es imprescindible realizar el paso del registro DNS antes que el alta del dominio, porque Azure realiza una consulta para verificar que el nuevo dominio apunta al dominio original de Azure.

Una vez que se aplican los cambios y, si todo ha ido correctamente, ya podemos acceder al site con el nuevo dominio:

Azure-CustomDomain

Podemos utilizar tanto un dominio de primer nivel (www.mi-dominio.com), como un subdominio (blog.mi-nombre.com). El único requisito es que el dominio resuelva con un alias al dominio original de azurewebsites.net.

Y con estos sencillos pasos, ya tenemos nuestro propio dominio funcionando con nuestra web en Azure.