Materiales del evento: Sevilla Mobility Day Strikes Back

El pasado sábado 26 de octubre con motivo de la segunda edición del Sevilla Mobility Day tuve la ocasión de dar una pequeña charla sobre las diferentes opciones de comunicación que tienen nuestras apps con el exterior:

IMG_5474

Slides

Las slides están disponibles a continuación en slideshare:

Demos

Por otra parte, las demos están disponibles en el siguiente enlace de Github:

https://github.com/rlbisbe/demos_charla_conectividad_wp

Enlaces

Y finalmente, la lista de enlaces que usé (entre otros) para preparar la charla:

Gracias los chicos de @cartujadotnet por la invitación, a CampusMVP por el patrocinio, al servicio técnico de Pebble por intentar echarme una mano, a mi querida Patrica Vasco (Patu) por ayudarnos con las fotos y en general a todos los que hicieron el evento posible.

Vídeo: Lo que viene con C# 6

En este evento tuvimos la ocasión de juntarnos varios entusiastas de tecnologías Microsoft para comentar lo que viene con la nueva versión de C# y Visual Studio 14, así como las novedades a nivel de compilador con Roslyn. Además tuvimos la posibilidad de contar con Syncfusion como patrocinador estrella, que ofreció una licencia de su producto Essential Studio Enterprise Edition a un asistente.

Tras una introducción a cómo poner a punto un Visual Studio 14 para empezar a jugar por parte de Juan Quijano (@jc_quijano) usando las máquinas virtuales de Azure, el ilustre Eduard Tomás (@eiximenis) y un servidor nos metíamos en harina para repasar algunas de las características que trae esta nueva versión del lenguaje.

Entre las novedades destacan la propagación de nulos, los constructores principales, o la inicialización de variables dentro de bloques, y por otro lado, de manera un tanto negativa también para los asistentes, de la importación de métodos de clases estáticas.

En el segundo bloque, de mano de Juan Manuel Servera (@jmservera) vimos cómo podemos extender las capacidades de Visual Studio a través de Roslyn, para agregar más capas o reglas a nuestro propio código, ofreciendo además la posibilidad de dar sugerencias a los desarrolladores, y todo esto en un paquete nuget que puede formar parte de nuestro código fuente.

Se avecinan tiempos muy interesantes en el desarrollo de IDEs.

Antes de terminar, no quería dejar de compartir algunas estadísticas del evento:

  • 10 +1s en la página del evento
  • 24 asistentes de máxima
  • 32 personas han visto el evento, de acuerdo con su estatus en la página de Google Plus.
  • 85 tweets (incluyendo retweets) con el hashtag #vienecsharp6, “oficial” del evento, de acuerdo con las estadísticas de Topsy
  • 108 visitas a la página del evento, de acuerdo con las estadísticas de Karmacracy.
  • 124 visualizaciones del vídeo en Youtube en este momento.

Finalmente, en el vídeo comentamos algunos enlaces que se muestran a continuación:

Muchas gracias a los ponentes por hacer el evento posible, a nuestro patrocinador por el apoyo y finalmente a todos los asistentes.

Eventazo: Sevilla Mobility Day Strikes Back

El próximo sábado 25 de octubre de 9 a 14:30 tendré el privilegio de compartir escenario con figuras como Javier Suarez, Josue Yeray, Asier Marques, Pedro J Molina o Juan María Lao en la segunda edición de Sevilla Mobility Day, organizada por el grupo Cartuja.NET.

Fuente: Flickr

Esta es la agenda, hay muchísimo contenido para poco más de 5 horas:

  • 9:00h – 9:05h: Bienvenida.
  • 9:10h – 9:50h: Javi Suarez realizará un recorrido por todos los aspectos a tener en cuenta para integrar nuestras aplicaciones Windows Phone con Cortana.
  • 9:55h – 10:35h: Josué Yeray nos introducirá Fortumo Mobile Payments, sistema de pago en aplicaciones universales.
  • 10:50h – 11:30h: Un servidor contará sus peripecias conectando Windows Phone con otros dispositivos.
  • 11:35h – 12:15h: De la mano de Asier Marques tendremos una interesante sesión donde aprenderemos a realizar WebApps.
  • 12:20h – 13:00h: Tras tanto fronted nos llega el turno del backend. Pedro J. Molina nos explicará como crear backends para nuestras aplicaciones con App Now.
  • 13:05h – 15:45h: David Rodriguez nos cuenta su experiencia con GeoMotion, App móvil asociada al localizador GPS para automóviles desde su inicio hasta hoy día.
  • 13:50h – 14:30h: Finalizamos el evento con una interesante y muy divertida mesa redonda junto a Juan María Lao, ¿TDD a favor o en contra?

El evento promete y solamente espero estar a la altura. Si estás en Sevilla o alrededores, ya estás tardando en apuntarte. Las slides y los ejemplos de código estarán disponibles, como de costumbre, poco después de la charla.

Te veo allí!

Editando las connection strings “en caliente” de un proyecto ASP.net

Un problema peculiar con el que me he encontrado recientemente tiene que ver con dos equipos con la misma base de código y un punto de sincronización común, que en este caso es o bien dos bases de datos distingas del mismo servidor, o a la misma base de datos con diferentes credenciales, en un gráfico como el que se muestra.

Capture

Para guardar la configuración de la base de datos recurrimos habitualmente al apartado connectionStrings de nuestro fichero web.config. Dicho fichero cuenta además con diferentes transformaciones según la configuración de build seleccionada, como muestra la siguiente imagen:

Capture_debug

Pero… las transformaciones solamente se ejecutan al desplegar un proyecto…

El hecho de no poder ejecutar las transformaciones en tiempo de compilación no nos permite depurar nuestra solución con las cadenas de conexión necesarias, y, aunque existe una manera de transformar el fichero web.config durante la compilación, quería buscar una aproximación diferente.

Editando el objeto ConnectionStrings

Dentro del código de nuestra aplicación disponemos del objeto ConfigurationManager.ConnectionStrings que nos da una colección de solo lectura en la que podemos acceder a los datos. Si intentamos escribir en dicha colección obtenemos la siguiente excepción:

An exception of type 'System.Configuration.ConfigurationErrorsException' occurred in System.Configuration.dll but was not handled in user code

Additional information: The configuration is read only.

Sin embargo si vamos al código fuente de ConnectionStrings veremos que el atributo connectionString tiene setter, con lo cual en teoría podemos fijar el valor:

public string ConnectionString {
    get {
        return (string)base[_propConnectionString];
    }
    set {
        base[_propConnectionString] = value;
    }
}

Si vamos un poco más abajo nos encontraremos con la clase ConfigurationElement, cuyo método IsReadOnly() se comprueba al intentar fijar un valor.

protected void SetPropertyValue(ConfigurationProperty prop, object value, bool ignoreLocks) {
if (IsReadOnly()) {
    throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
}

public virtual bool IsReadOnly() {
    return _bReadOnly;
}

Este valor IsReadOnly lee una variable _bReadOnly, y no sería maravilloso que pudiéramos editar esa variable y editar nuestras cadenas de conexión? Pues gracias a Reflection podemos hacerlo!:

ConnectionStringSettings connectionString = ConfigurationManager.ConnectionStrings[0];
var field = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(connectionString, false);
connectionString.ConnectionString = "CustomConnectionString";
field.SetValue(connectionString, true);

Tras nuestra edición podemos volver a establecer el atributo _bReadOnly a true restaurando el bloqueo de la escritura. Hemos de tener en cuenta que este proceso ha de realizarse lo antes posible en nuestra aplicación, así que yo usaría Startup.cs o Global.asax.cs (recordemos que este último desaparece con ASP.net vNext).

Cargando nuestras connection strings personalizadas

Una vez que sabemos que podemos cargar las connection strings en caliente, el siguiente paso es cargar el fichero que contiene las transformaciones:

string path = HostingEnvironment.MapPath("~/Web.TEAM1.config");
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNodeList list = doc.DocumentElement.SelectNodes(string.Format("connectionStrings/add[@name='{0}']", "Title"));
XmlNode node = list[0];
string connectionStringToReplace = node.Attributes["connectionString"].Value;

En este caso cargamos el fichero de TEAM1, buscamos la cadena de conexión con la clave especificada y la asignamos a la variable connectionStringToReplace.

Código completo

private void ReplaceConnectionStrings(string team)
{
    string path = HostingEnvironment.MapPath(string.Format("~/Web.{0}.config", team));
    XmlDocument doc = new XmlDocument();
    doc.Load(path);

    foreach (ConnectionStringSettings connectionString in ConfigurationManager.ConnectionStrings)
    {
        XmlNodeList list = doc.DocumentElement.SelectNodes(string.Format("connectionStrings/add[@name='{0}']", connectionString.Name));
        if (list.Count == 0) continue;

        XmlNode node = list[0];

        var field = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
        string connectionStringToReplace = node.Attributes["connectionString"].Value;

        field.SetValue(connectionString, false);
        connectionString.ConnectionString = connectionStringToReplace;
        field.SetValue(connectionString, true);
    }
}

Este código recorre todas las Connection Strings, y si encuentra una en nuestro fichero de transformaciones, la reemplaza.

Finalmente, directivas de preprocesador

Las configuraciones de Build nos permiten fijar ciertas directivas a nuestros proyectos, y estas directivas se aplicarán en tiempo de compilación. De esta manera si alguna de las dos claves está presente se sustituirán, en caso de que ninguna esté presente no se realizará una sustitución.

#if TEAM1
    ReplaceConnectionStrings("TEAM1");
#elif TEAM2
    ReplaceConnectionStrings("TEAM2");
#endif

A continuación se pueden ver dos ejemplos para los diferentes equipos.

Capture_team1

Capture_team2

Conclusiones

Esta solución nos da una manera efectiva de poder depurar nuestro código sin afectar el ciclo de vida del fichero web.config, sus transformaciones, y el comportamiento por defecto. El código agregado solamente se ejecutaría en caso de que alguna de las dos directivas se cumpliese, con lo cual podemos tener diferentes configuraciones para diferentes equipos.

Reflection es una característica que nos permite sacar mucho más de lo que un objeto nos ofrece públicamente, a costa de un impacto en rendimiento y requerir un mayor conocimiento de lo que estamos haciendo, de ahí a que se use con moderación.

Enlaces adicionales

Eliminando acoplamiento en un controlador ASP.net MVC

Cuando desarrollamos aplicaciones web podemos caer en el error de dar demasiada responsabilidad a nuestros controladores lo que nos puede traer problemas en el futuro al intentar refactorizar ese código.

En este artículo veremos cómo partiendo de una acción donde la carga de datos se realiza desde el propio controlador podemos reducir el acoplamiento a la manera de guardar los datos. Con ello conseguiremos mejorar la reusabilidad y legibilidad del mismo, así como permitir realizar pruebas unitarias o cambiar componentes de manera sencilla.

Código inicial

Nuestro primer código es un simple controlador con un método que lista un catálogo de libros. Este controlador contiene un método que lista un catálogo de libros. Usaremos directamente sentencias SQL contra una base de datos LocalDB.

public class HomeController : Controller
{
    public ActionResult Books()
    {
        List<Book> books = new List<Book>();
        SqlConnection connection = new SqlConnection(@"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Books.mdf;Integrated Security=True");
        SqlCommand cmd = new SqlCommand();
        SqlDataReader reader;

        cmd.CommandText = "SELECT Title,Author FROM [Table]";
        cmd.CommandType = CommandType.Text;
        cmd.Connection = connection;

        connection.Open();

        reader = cmd.ExecuteReader();
        if (reader.HasRows)
        {
            while (reader.Read())
            {
                books.Add(new Book
                {
                    Title = reader.GetString(0),
                    Author = reader.GetString(1)
                });
            }
        }

        connection.Close();
        return View(books);
    }
}

El resultado es una lista de objetos de tipo Book, que es un POCO (Plain Old C# Object) que contiene dos campos, Title y Author. La principal desventaja, y es la que intentaremos resolver a lo largo de este artículo, es que presenta un fuerte acoplamiento con el gestor de base de datos, y si cambiamos a MySQL o MongoDB, por poner un ejemplo, nos veríamos obligados a reescribir la esta implementación.

Primera aproximación, patrón Repository

El objetivo de un patrón Repository es crear una capa de abstracción entre la lógica de negocio (representada en este caso por el controlador) y la lógica de base de datos (representada por el acceso a SQL). Dicha capa de abstracción nos permite probar nuestro controlador de manera independiente a los datos y a la manera de almacenar los mismos.

La implementación de un patrón repository la podemos realizar usando una interfaz y su correspondiente implementación:

public interface IBookRepository
{
    List<Book> GetAllBooks();
}

public class BookRepository : IBookRepository
{
    private SqlConnection _connection;
    private string _connectionString = @"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Books.mdf;Integrated Security=True";
    public BookRepository()
    {
        _connection = new SqlConnection(_connectionString);
    }

    public List<Book> GetAllBooks()
    {
        List<Book> books = new List<Book>();
        SqlCommand cmd = new SqlCommand();
        SqlDataReader reader;

        cmd.CommandText = "SELECT Title,Author FROM [Table]";
        cmd.CommandType = CommandType.Text;
        cmd.Connection = _connection;

        _connection.Open();

        reader = cmd.ExecuteReader();
        if (reader.HasRows)
        {
            while (reader.Read())
            {
                books.Add(new Book
                {
                    Title = reader.GetString(0),
                    Author = reader.GetString(1)
                });
            }
        }

        _connection.Close();
        return books;
    }
}

El código de la implementación es el mismo, ya que seguimos usando SQL para el acceso a datos, sin embargo hemos creado una abstracción que nos permite realizar pruebas unitarias y dejar los detalles de la implementación del acceso a datos al Repositorio.

El código del controlador se reduce al código siguiente:

public class HomeController : Controller
{
    private IBookRepository _bookRepository;

    public HomeController()
    {
        _bookRepository = new BookRepository();
    }

    public ActionResult Books()
    {
        return View(_bookRepository.GetAllBooks());
    }
}

Pese a que el repositorio se inicia desde el controlador, podríamos usar una solución de inyección de dependencias como Ninject o crear nuestra propia solución para que la inicialización de las dependencias se realice fuera del mismo.

Reduciendo acoplamiento en nuestro Repositorio

Una vez tenemos separados el controlador y el repositorio, tenemos varias alternativas para mejorar la legibilidad y la facilidad de uso del código

LINQ to SQL

Usar LINQ to SQL nos permite realizar un mapeado directo entre nuestra tabla y una clase, así como una capa de abstracción adicional sobre nuestro repositorio.

public class LinqToSqlBookRepository : IBookRepository
{
    private DataContext _db;
    private string _connectionString = @"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Books.mdf;Integrated Security=True";
    public LinqToSqlBookRepository()
    {
        _db = new DataContext(_connectionString);
    }

    public List<Book> GetAllBooks()
    {
        Table<Book> book = _db.GetTable<Book>();
        return book.ToList<Book>();
    }
}

Para que el mapping funcione correctamente, hemos de decorar nuestro modelo con los nombres de las columnas equivalentes:

[Table(Name = "Table")]
public class Book
{
    [Column(Name = "Title")]
    public string Title { get; set; }
        
    [Column(Name = "Author")]
    public string Author { get; set; }
}

Esta aproximación nos da una capa de abstracción mayor, comprobación de tipos en tiempo de compilación, capacidad de debug, y facilidad de acceso, a costa de perder algo de flexibilidad y rendimiento.

Conclusiones y pasos adicionales

LINQ to SQL no es la única manera de agregar abstracciones a nuestros datos, también podemos usar sistemas más complejos como Entity Framework, NHibernate, o Massive, siendo este el último que he descubierto y al que espero dedicarle pronto un artículo. Cada capa de abstracción, como decíamos anteriormente, nos permite desacoplar el código que estamos usando, aumentar su facilidad para ser probado, y su legibilidad, a la vez que cumplimos con principios como el de responsabilidad simple.

El proyecto termina con 3 capas diferenciadas:

  • Capa de presentación (Controlador)
  • Capa de datos (Repositorio)
  • Capa de persistencia (SQL)

Podemos agregar capas de lógica de negocio (si queremos realizar validaciones sobre los datos antes de que lleguen a la base de datos) o de servicio (si tenemos varias interfaces para nuestra aplicación). Cada capa aumenta la complejidad de nuestra aplicación pero también aumenta nuestra capacidad para limitar las responsabilidades de cada clase.

Puedes ver el código completo en github

Lecturas adicionales

Extra: Código de creación de la base de datos y datos de ejemplo

El código de creación de la base de datos y de los datos de ejemplo también es muy simple (SQL)

CREATE TABLE [dbo].[Table]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY, 
    [Title] NVARCHAR(50) NULL, 
    [Author] NVARCHAR(50) NULL
)
INSERT INTO [dbo].[Table] (Title,Author) VALUES ('Hamlet', 'William Shakespeare')
INSERT INTO [dbo].[Table] (Title,Author) VALUES ('El Ingenioso Hidalgo Don Quijote de la Mancha', 'Miguel de Cervantes y Saavedra')
INSERT INTO [dbo].[Table] (Title,Author) VALUES ('La divina comedia', 'Dante Alighieri')

Adding multiple languages to a Windows Store app with Javascript and Angular

Leer este artículo en castellano aqui

Last thursday I could attend a debate organized by MSCoders Madrid user group, related with localization of apps in a web enfironment.

After the event I got interested in frontend localization with Javascript. As Karmacracy for Windows is a Javascript app, I decided to do some experimentation on localizing the user interface in the context of a Windows Store app, to be able to distribute it for other markets.

Detecting the system language

For a Windows Store app the first thing to do is to detect the sustem language. This can be archieved with the following piece of code:

var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
var language = culture.substr(0, 2);

The culture is the language that is currently being used for the UI, in culture format. For example for Spanish of Spain would be es-ES, for US English would be en-US, and for British English would be en-GB. To be able to change this order and deploy our app, we must go to the control panel:

Captura de pantalla 2014-09-15 00.29.43

In this example we only need the language, not the culture, so we are going to get a substring of the culture getting en, es, de, etc.

Adding angular-translate

Angular-translate is a module that allows us to define key-value pairs for each language and perform the translation according to the configuration. For installing it, if we don’t use a package manager such as bower, we must download the last package from github and add it to our project.

Once installed, we must add it to the configuration of our app, in the section we define external modules (in this case the module is pascalprechtr.translate).

var karmacracyApp = angular.module('karmacracyApp', [
    'ngRoute',
    'karmacracyControllers',
    'pascalprecht.translate'
]);

Finally, we configure the different languages by using the code we defined previously for getting the OS display language:

karmacracyApp.config(['$translateProvider', function ($translateProvider) {
    $translateProvider.translations('en', {
        'LOGIN': 'Log in',
        'LOGIN_USERNAME': 'User name',
        'LOGIN_PASSWORD': 'Password'
    });

    $translateProvider.translations('es', {
        'LOGIN': 'Inicia sesión',
        'LOGIN_USERNAME': 'Nombre de usuario',
        'LOGIN_PASSWORD': 'Contraseña'
    });

    var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
    var language = culture.substr(0, 2);

     $translateProvider.preferredLanguage(language).fallbackLanguage('en');
}]);

Also, in case the current language is not available, we set English by default

#Usage

For accessing our keys we don’t need any aditional configuration on our controllers, we just need to modify our views so they can access the localized information

<span class="loginMessage">{{ 'LOGIN' | translate }}</span>

If the language is set to English or other language not controlled, the result will be the following:

en

If the language is set to spanish, the result will be the following:

es

As it shows, is an easy way to localize our javascript apps for the Windows Store.

Recap and next steps

Angular-translate provides a simple way of localizing texts in our views and Windows provides the information we need for setting the current language of an app.

As an aditional step, we may try to localize winjs controls such as buttons, which work in a very different way. Angular-translate also supports loading the translations from a json files, an option that may be useful if we want to distribute those files for translation by 3rd parties.

Links

Agregando múltiples idiomas a una aplicación de Windows Store con Javascript y Angular

**Read this article in English here

El pasado jueves tuve la ocasión de asistir a una mesa redonda organizada por el grupo MSCoders relacionada con la localización de aplicaciones en entornos web.

Tras el evento, uno de los temas que más llamó mi atención fue la localización en la parte Javascript, y como tenía una aplicación ya en la Windows Store que usaba ese lenguaje, me pareció interesante intentar localizarla para poder ofrecerla en otros mercados.

Detectando el idioma del sistema

Para una aplicación Windows 8 el primer paso es detectar el idioma del sistema, y eso lo podemos hacer de la siguiente manera:

var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
var language = culture.substr(0, 2);

En este caso tomaremos la lista de lenguajes preferentes, y de esa lista obtendremos el primer elemento. Para poder cambiar el orden de los elementos y probar los diferentes lenguajes, podemos cambiarlo en el panel de control:

Captura de pantalla 2014-09-15 00.29.43

El resultado se muestra en formato cultura, es decir, español de España se mostraría como es-ES, e inglés de EEUU se mostraría como en-US. Para nuestro ejemplo inicial, solamente necesitamos el idioma, con lo cual hacemos un substring y obtenemos en o es respectivamente.

Agregando angular-translate

Angular-translate es un módulo de angular que nos permite definir de manera las claves y los valores para cada lenguaje, y realizar la traducción en función de la configuración. Para instalarlo, si no contamos con gestores de paquetes como bower, es tan sencillo como descargar el último paquete de github y agregarlo a nuestro proyecto.

Una vez instalado, tendremos que agregarlo a la configuración de nuestra app, en el apartado en el que definimos módulos externos en este caso pascalprecht.translate:

var karmacracyApp = angular.module('karmacracyApp', [
    'ngRoute',
    'karmacracyControllers',
    'pascalprecht.translate'
]);

Finalmente, configuramos los diferentes idiomas usando el código que hemos visto anteriormente para seleccionar un idioma acorde con el sistema operativo:

karmacracyApp.config(['$translateProvider', function ($translateProvider) {
    $translateProvider.translations('en', {
        'LOGIN': 'Log in',
        'LOGIN_USERNAME': 'User name',
        'LOGIN_PASSWORD': 'Password'
    });

    $translateProvider.translations('es', {
        'LOGIN': 'Inicia sesión',
        'LOGIN_USERNAME': 'Nombre de usuario',
        'LOGIN_PASSWORD': 'Contraseña'
    });

    var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
    var language = culture.substr(0, 2);

    $translateProvider.preferredLanguage(language).fallbackLanguage('en');
}]);

Además, en caso de que el sistema tenga un idioma no controlado, estableceremos el inglés por defecto.

Uso

Para acceder a nuestras claves no necesitamos realizar ninguna configuración adicional en nuestros controladores, solamente necesitamos modificar nuestras vistas para que accedan a la información localizada:

<span class="loginMessage">{{ 'LOGIN' | translate }}</span>

En caso de que tengamos el idioma establecido a inglés (o a cualquier idioma no controlado), se mostrará el siguiente resultado:

en

En caso de que el idioma esté establecido a español, el resultado será diferente:

es

Como se ve, es una manera sencilla de poder localizar nuestras aplicaciones en javsacript para Windows Store

Conclusiones y pasos adicionales

Angular-translate proporciona una manera sencilla de localizar textos en nuestras vistas, por otra parte, Windows proporciona, a través de su API, la información que necesitamos para saber en qué idioma mostrar una aplicación.

Un paso adicional sería localizar controles winjs como los botones, que funcionan de manera diferente. Por otra parte se podría sacar un fichero de traducciones fuera de la configuración en formato json, útil si queremos distribuir esos ficheros para su procesamiento.

Enlaces adicionales