¿Es útil mi interfaz?

Empecemos por ver la definición de interfaz, que aunque es muy antigua, contiene mucha influencia en la programación “moderna” (IoC, DI, TDD, APIs, etc.) “Una interfaz es un contrato donde se especifican todos los términos y especificaciones que se deben cumplir para realizar y concretar algo”.

Olvidemos por un momento que hablamos de una interfaz y resaltemos algunas palabras claves en esta definición:

– Contrato
– Términos
– Especificaciones
– Cumplir
– Concretar

El contrato contiene términos y especificaciones, quien lo firme, las tendrá que cumplir y concretar. Un contrato podrá cambiar en el tiempo, pero será un cambio demandado y acordado por ambas partes y siempre se deberá entender como una evolución del mismo.

Volvamos a la interfaz e imaginemos la siguiente situación:

Día 1:
public interface IA
{
void M1();
}

Día 2:
public interface IA
{
void M1(int p1);
}

Día 3:
public interface IA
{
void M1(int p1, int p2);
}

Día 4:
public interface IA
{
int M1(int p1, int p2);
}

Se ha definido una interfaz porque necesitamos que todo aquel que la implemente, cumpla con todos sus términos y especificaciones. El problema aquí es que día tras día esta interfaz ha sufrido modificaciones que implican un cambio del contrato.

Esto por muchos motivos “obvios” no es bueno y las dos razones principales por lo que esto sucede son:

1- No tenemos claro los términos y a medida que vamos desarrollando nos damos cuenta de que tenemos que cambiarlos
2- No hemos recibido las especificaciones que dicho contrato debe cubrir y durante el proceso de desarrollo nos van cambiando.

¿Esto quiere decir que tengo que tener en mi cabeza todos los términos y especificaciones antes de escribir mi contrato? NO. Al principio comentamos que una interfaz puede cambiar, y un ejemplo claro es cuando ampliamos los términos para cubrir más especificaciones.

public interface IA
{
void M1();
}

Si necesitamos ampliar las especificaciones de esta interfaz, modificar la misma sería un error, ya que obligamos a que todos los firmantes tengan que cambiar para soportar las nuevas especificaciones. En este caso lo más correcto sería no afectar a quienes ya implementan esta interfaz y crear las nuevas especificaciones en una nueva interfaz que herede de la ya definida.

public interface IAA : IA
{
void M2(int p1, int p2);
}

La interfaz en un API :)

La documentación de un API es un contrato que contiene términos y especificaciones inviolables si no se quiere afectar a quienes nos consumen. Sería un error que con la documentación de un API ocurra lo mismo que con la interfaz IA, y esta cambie constantemente. Las causas son exactamente las mismas: no tenemos claro el flujo lógico de nuestra API y los términos cambian constantemente o, las especificaciones nos llegan a cuenta gotas.

Para decir que estamos listos para escribir la interfaz IA o la documentación de un API, hay que tener claro los términos de la mínima unidad funcional que vamos a llevar a cabo. No tiene que ser toda la lógica, ni siquiera tiene por qué ser la mitad o un tercio, simplemente tiene que ser lo mínimo necesario para que aquello que vamos a desarrollar, podamos plasmarlo en la interfaz o en la documentación.

¿Y cuando quiera ampliar las especificaciones en el caso de un API? Aquí es donde entra el versionado, que irá cambiando en cada modificación del contrato. El versionado de un API no es algo que se tiene en cuenta una vez puesta en producción, sino que va unido a cada paso que da el equipo durante el tiempo de desarrollo.

Imaginemos por último que además de modificar constantemente un contrato, no avisamos a los firmantes. Así, te enteras luego de una semana o un mes, que has estado trabajando por mucho menos de lo pactado o que tu hipoteca se ha incrementado en un 500%… ¿un caos verdad? ¿Qué pensarías de tu empresa o banco? ¿Qué pensarías del equipo que desarrolla la interfaz o el API?

Saludos

Mockeando Window.location

Estoy en un proyecto donde tengo que interactuar con servicios RestFul desde javascript. El problema que tengo es que estos servicios están aún en desarrollo por lo que cuando me toca trabajar con ellos puede que estén o no disponibles.

Para evitar detener mi trabajo cuando los servicios no están disponibles he decidido que los test trabajen con mocks. Hace unos días me tocó hacer un test para chequear un método que internamente hacía uso de window.location.

Hay muchas soluciones disponibles para testear nuestro método, veamos una de ella:

  1. var MyNamespace = new function()
  2. {
  3.     this.MyObject = function(win)
  4.     {
  5.         var __win = win;
  6.  
  7.         this.NavigateTo = function(p1, p2)
  8.         {
  9.             var __url = "http://www.google.com/?q=" + p1 + "&s=" + p2;
  10.             __win.location.href = __url;
  11.         };
  12.     };
  13. };

Este sería nuestro objeto en javascript el cual contiene un método llamado NavigateTo y al que le pasamos dos parámetros para formar una url.

Probar este método es muy fácil: (usaremos qunit por su cómoda integración con ReSharper)

  1. test("Window location", function ()
  2. {
  3.     var __winMock = { location: { href: "" }};
  4.     var __myObj = new MyNamespace.MyObject(__winMock);
  5.  
  6.     __myObj.NavigateTo('abc', 'def');
  7.  
  8.     window.equal("http://www.google.com/?q=abc&s=def", __winMock.location.href, "is ok");
  9. });

Nuestro test pasa sin problemas.

moc-1

En el momento en que necesitemos que nuestro objeto trabaje con el objeto real, solo tenemos que pasar el window en el constructor.

  1. var __myObj = new MyNamespace.MyObject(window);

Otra solución y mi preferida, es encapsular la llamada a window.location.href en una función que podamos usar desde cualquier parte en nuestro proyecto. Luego solo tendríamos que mockear la función y testear que todo esté correcto.

  1. var MyNamespace = new function ()
  2. {
  3.     this.MyObject = function ()
  4.     {
  5.         this.NavigateTo = function (p1, p2)
  6.         {
  7.             var __url = "http://www.google.com/?q=" + p1 + "&s=" + p2;
  8.             Utils.Browser.Navigate(__url);
  9.         };
  10.     };
  11. };
  12.  
  13. var Utils =
  14. {
  15.     Browser: new function()
  16.     {
  17.         this.Navigate = function (url)
  18.         {
  19.             window.location.href = url;
  20.         };
  21.     }
  22. };

Aquí ya no estamos falseando el objeto window sino que encapsulamos su utilización dentro de un objeto Browser que contiene un método llamado  Navigate.

Para testear el ejemplo anterior, vamos a usar Sinon y su pluging para qunit. Como estamos trabajando con ReSharper para las pruebas, debemos indicar la referencia a estos frameworks en nuestro js de pruebas.

  1. /// <reference path="/resources/sinon-1.5.2.js"/>
  2. /// <reference path="/resources/sinon-qunit-1.0.0.js"/>

Ya con esto podemos crearnos nuestro test:

  1. test("Window location", function ()
  2. {
  3.     var __myObj = new MyNamespace.MyObject();
  4.  
  5.     var __mock = sinon.mock(Utils.Browser);
  6.     __mock.expects("Navigate").once().withArgs("http://www.google.com/?q=abc&s=def");
  7.  
  8.     __myObj.NavigateTo('abc', 'def');
  9.  
  10.     __mock.verify();
  11. });

y el resultado…

moc-1

Lo que me gusta de este método respecto al anterior es que no tenemos necesidad de falsear un objeto nativo del DOM. Por el contrario, lo que hacemos es mokear un objeto nuestro y testear su funcionalidad.

Microsoft Hosted Network Virtual Adapter

…o lo que es lo mismo, un router virtual WIFI en mi ordenador. :) …y aquí es donde quizás los de IT digan: ¿Y ahora es que te enteras…?

Resulta que el próximo martes toca realizar una presentación de una aplicación Web y para la cual necesitamos que estén conectados a una misma red: dos ordenadores, un iPad y un Tablet con Windows 8.

Posibles soluciones y problemas:

1- WIFI
Solución: Espero a que el lugar de la presentación tenga WIFI, y además el salón tenga cobertura.

Problema: Pierdes tiempo configurando conexiones en los dispositivos, problemas de coberturas, la primera impresión que se deja es un poco de “estamos perdiendo tiempo”

2- Router WIFI
Solución: Me llevo un Router WIFI previamente configurado y conecto a todo el mundo: Imaginen llegar, sacar un iPad, un tablet de W8, dos ordenadores, una kinect y un router con antenita al estilo “Star Wars light sabers” :)

Problemas: Necesito un router físico y más conectores de alimentación

3- Tengo un Nokia Lumia 800
Solución: Puedo activar “Compartir conexión” lo cual activa en mi teléfono un host WIFI al cual puedo conectar a todo el mundo.

Problemas: Pobre Nokia Lumia… ¿Cuanto dudará la batería? :)

4- Si el teléfono crea un Host WIFI virtual, ¿no podré hacer lo mismo en mi ordenador? Googleando…

Solución: Mi querido amigo netsh

Pues bien, como este trabajo no es de desarrollo sino de IT, en vez de cargar Visual Studio 2012, cargamos la consola de comandos “cmd” y, recuerden que tienen que hacerlo con permisos de administración…

wifi-1

Ejecutamos un primer comando:
netsh wlan set hostednetwork mode=allow ssid=odelvalle key=MyPassword

wlan: Wireless Lan (vamos a trabajar sobre la conexión WIFI)
set hostednetwork: (vamos a trabajar con las propiedades del hostednetwork).

El hostedNetwork es una funcionalidad soportada en W7, W8 y los 2008R2 en adelante…  Su principal objetivo es (para IT) virtualizar un adaptador wireless (para desarrolladores) un router WIFI de toda la vida.

El resto de los comandos indican si vamos a permitir conexión (mode), el nombre que le pondremos a nuestra WIFI (ssid) y la contraseña (key).

Todo lo anterior configura y deja listo nuestro hostednetwork, pero necesitamos echarle a funcionar y, para eso ejecutamos un segundo comando:

netsh wlan start hostednetwork

Este segundo comando inicia el  hostednetwork y deja nuestra vista de adaptadores de red de la siguiente forma:

wifi-2

y mi Nokia Lumia….

Screen Capture

Espero q a alguien le sirva…. Salu2

RESTFul en Windows 8

Para las aplicaciones que he realizado para WP7 tenía un helper que me ayudaba a consultar servicios RESTful, pero la verdad, con todo el tema de async, await y Task, es motivo suficiente como para plantearse rescribir cualquier código asíncrono escrito con anterioridad.

Para nuestro helper vamos a necesitar fundamentalmente 2 clases, aunque implementaremos una tercera clase para el tema de serialización.

A todas las clases les vamos a definir una interfaz, las ventajas ya las conocemos: no atamos las clases que usen nuestro helper a nuestra implementación y además, podremos inyectar el helper usando IoC si trabajamos con MVVM.

Empecemos justo por la clase que se encargará de serializar y de-serializar:

public interface IJsonResolver
{
    Task<byte[]> Serialize(object graph);
    Task<T> Deserialize<T>(Stream respnseResult) where T : class;
}

Nuestra interfaz tiene dos métodos que nos permitan serializar y de-serializar nuestros objetos. Estos métodos retornan un Task, por lo que podremos usar su condición asíncrona durante la implementación.

En mi caso, voy a usar Json.net para implementar esta interfaz, pero ustedes pueden elegir su propia implementación.

public class JsonResolver : IJsonResolver
{
    private async Task<string> SerializeToString(object graph)
    {
        return await JsonConvert.SerializeObjectAsync(graph, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
    }

    public async Task<byte[]> Serialize(object graph)
    {
        if (graph is string) return Encoding.UTF8.GetBytes(graph as string);

        var json = await SerializeToString(graph);
        return Encoding.UTF8.GetBytes(json);
    }

    public async Task<T> Deserialize<T>(Stream respnseResult) where T : class
    {
        T result;

        using (var sr = new StreamReader(respnseResult))
        {
            var r = await sr.ReadToEndAsync();
            result = await JsonConvert.DeserializeObjectAsync<T>(r, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
        }

        return result;
    }
}

Ya tenemos nuestra implementación, vamos a lo que de verdad nos interesa.

La utilización de un servicio web, ya sea Rest, Xml o cualquier otro formato, está compuesto principalmente por dos elementos:

  1. El Request: Este elemento podría contener la URL a la cual vamos a realizar la petición, qué tipo de petición vamos a realizar (si es GET, POST, u otra), el ContentType, los parámetros, etc…
  2. Un cliente que realiza la petición usando todas las opciones definidas en el Request.

Siguiendo esta lógica, mi Helper tendrá dos clases más: un RestRequest y un RestClient.

Vamos a definir la interfaz para el RestRequest.

public interface IRestRequest
{
    Uri Url { get; }
    string PostParameter { get; }
    Method Method { get; }
    string Accept { get; }
    string ContentType { get; }

    /// <summary>
    /// Add Parameter to URL. Value is not encode. If Method is POST, parameter is pass in body, if Method is Get, parameter is pass in URL.
    /// </summary>
    /// <param name="name">Parameter name</param>
    /// <param name="value">Parameter value</param>
    void AddParameter(string name, string value);

    /// <summary>
    /// Add Parameter to URL. This method encode parameter value by default
    /// </summary>
    /// <param name="name">Parameter name</param>
    /// <param name="value">Parameter value</param>
    /// <param name="pType"> </param>
    void AddParameter(string name, string value, ParameterType pType);

    /// <summary>
    /// Add Parameter to URL. This method encode parameter value by default
    /// </summary>
    /// <param name="name">Parameter name</param>
    /// <param name="value">Parameter value</param>
    /// <param name="encode"> </param>
    void AddParameter(string name, string value, bool encode);

    /// <summary>
    /// Add Parameter to URL. 
    /// </summary>
    /// <param name="name">Parameter name</param>
    /// <param name="value">Parameter value</param>
    /// <param name="encode">if true, encode parameter value</param>
    /// <param name="pType"></param>
    void AddParameter(string name, string value, bool encode, ParameterType pType);
}

En esta interfaz tenemos varios elementos que nos ayudan a configurar nuestro Request antes de realizar la petición.

El método AddPArameter cuenta con varias sobrecargas ya que vamos a tener varias posibilidades de pasar parámetros. Vamos a verlo uno por uno empezando por el más complejo (el último):

  1. Este método recibe un nombre, un valor, permite indicar si el valor del parámetro debe ser “encodeado” o no y el tipo de parámetro que estamos utilizando.
    1. El “encodear” el valor de un parámetro es usado fundamentalmente cuando pasamos el valor por GET, ya que hay caracteres que no son válidos como parte de la URL
    2. ParamType es un enumerado que me indica el tipo de parámetro que vamos a pasar a nuestro objeto: QueryString (GET?nombre=valor), Post (se pasa en el body) y UrlSegment que es utilizado cuando el parámetro es parte de la URL. Ej. http://odelvalle.com/{parametro}/Rest
  2. Un segundo método en que no es necesario pasar el tipo de parámetro. En este caso el tipo es determinado según el método usado para el Request, si es GET se pasa por QueryString, si es Post, se pasa en el body.
  3. Otro método que nos permite indicar solo el nombre, el valor y el tipo de parámetro. Todos los parámetros pasados mediante este método, el value es “encodeado”.
  4. Finalmente, tenemos un método que nos vale para pasar solo el nombre y el valor. Los parámetros que se pasen usando esta sobrecarga no se van a “encodear” y el tipo de parámetro es determinado por el tipo de Request (GET o POST)

Las propiedades definidas en la interfaz nos brindan el resto de la información necesaria para formar nuestro Request. Vamos a ver la implementación

public enum ParameterType
{
    QueryString,
    Post,
    UrlSegment
}

public enum Method
{
    GET,
    POST,
    PUT,
    DELETE,
    HEAD,
    OPTIONS,
    PATCH
}

public enum ContentType { Json, UrlEncoded }

public class RestRequest : IRestRequest
{
    struct Parameter
    {
        public string Name { get; set; }
        public string Value { get; set; }

        public ParameterType ParameterType { get; set; }
    }

    private readonly IList<Parameter> _parameters;

    private readonly string _url;
        
    public RestRequest(string url, Method method)
    {
        _parameters = new List<Parameter>();
        _url = url;

        Method = method;
    }

    public Uri Url
    {
        get
        {
            var buildUri = new UriBuilder(_url) { Query = BuildQueryString(ParameterType.QueryString) };
            return buildUri.Uri;
        }
    }

    public string PostParameter { get { return BuildQueryString(ParameterType.Post); }}
    public Method Method { get; private set; }

    public string Accept { get { return "application/json"; }}
    public string ContentType { get { return "application/x-www-form-urlencoded"; } }

    public void AddParameter(string name, string value)
    {
        AddParameter(name, value, false);
    }

    public void AddParameter(string name, string value, ParameterType pType)
    {
        AddParameter(name, value, true, pType);
    }

    public void AddParameter(string name, string value, bool encode)
    {
        AddParameter(name, value, encode, (Method == Method.GET) ? ParameterType.QueryString : ParameterType.Post );
    }

    public void AddParameter(string name, string value, bool encode, ParameterType pType)
    {
        var val = encode ? Uri.EscapeDataString(value) : value;

        if (pType == ParameterType.UrlSegment) _url.Replace(string.Format("{{0}}", name), val);
        else _parameters.Add(new Parameter { Name = name, Value = val, ParameterType = pType});
    }

    private string BuildQueryString(ParameterType pType)
    {
        var plist = _parameters.Where(p=> p.ParameterType == pType).Select(p => string.Concat(p.Name, "=", p.Value));
        return String.Join("&", plist.ToArray());
    }
}

Al constructor de la clase RestRequest le vamos a pasar la URL a la cual queremos realizar la petición y el método a utilizar.

Ya con esto tenemos nuestro RestRequest, vamos a ver el cliente que realizará la petición. Empezamos viendo la interfaz:

public interface IRestClient
{
    Task<T> Execute<T>(IRestRequest request) where T : class;
}

.. y eso es todo. No necesitamos nada más ya que estamos definiendo un cliente que recibirá un objeto RestRequest y hará una petición. Veamos la implementación.

public class RestClient : IRestClient
{
    private readonly IJsonResolver _resolver;

    public RestClient(IJsonResolver resolver)
    {
        _resolver = resolver;
    }

    public async Task<T> Execute<T>(IRestRequest request) where T : class 
    {
        var wr = WebRequest.CreateHttp(request.Url);

        wr.Method = request.Method.ToString();
        wr.Accept = request.Accept;
        wr.ContentType = request.ContentType;

        if (!string.IsNullOrEmpty(request.PostParameter))
        {
            return await ExecuteWithData<T>(wr, request);
        }

        var response = await wr.GetResponseAsync();
        return await _resolver.Deserialize<T>(response.GetResponseStream());
    }

    private async Task<T> ExecuteWithData<T>(WebRequest wr, IRestRequest request) where T : class
    {
        var body = await _resolver.Serialize(request.PostParameter);

        using (var stream = await wr.GetRequestStreamAsync())
        {
            await stream.WriteAsync(body, 0, body.Length);
        }

        var response = await wr.GetResponseAsync();
        return await _resolver.Deserialize<T>(response.GetResponseStream());
    }
}

Nuestro cliente recibe en el constructor el RestRequest que se desea realizar. Mediante el método Execute, el cliente se encarga de realizar la petición y si hay respuesta del servicio Rest, entonces nos retornará el objeto listo para usarse.

Para probar todo esto y ver lo simple que es de usar, me busqué alguna ejemplo Rest que ya existiera para Windows 8.  Aquí tenéis una: Metro client for Web API CRUD

En esta aplicación al final de la clase MainViewModel.cs tenemos el GET usando HttpClient y DataContractJsonSerializer.

using (var http = new HttpClient())
{
    var resp = await http.GetAsync(new Uri(ApiRoot));
    using (var stream = await resp.Content.ReadAsStreamAsync())
    {
        var djs = new DataContractJsonSerializer(typeof(List<Person>));
        People = new ObservableCollection<Person>((IEnumerable<Person>)djs.ReadObject(stream));
    }
}

Vamos a quitar ese código y vamos a usar el nuestro:

var request = new RestRequest(ApiRoot, Method.GET);
var restFul = new RestClient(new JsonResolver());

People = new ObservableCollection<Person>(await restFul.Execute<IEnumerable<Person>>(request));

… ¿probamos?

screenshot_10112012_004023

Aquí dejo la aplicación de ejemplo modificada y usando nuestro Helper.

PD: Aún no he probado todo el Helper, así que es posible que en un escenario específico pueda aparecer algún BUM Sonrisa

Carga de páginas en Chrome, rápido sí, pero ¿seguro?

Estoy haciendo una aplicación que usa Web Socket. Como navegador, por políticas del cliente, se está usando Chrome.

Resulta que en unas de mis pruebas, descubro algo que al menos a mi, me deja un “tin” preocupado respecto a Chrome.

Observen:

chrome

Lo que está pasando aquí es que yo abro Chrome, comienzo a escribir la URL y el navegador me propone la URL a usar. El problema es que yo aún no he confirmado que es esa, ni siquiera le he dicho a Chrome que navegue a esa URL, pero ya mi servidor de Web Socket ha detectado una conexión entrante.

¿Entonces?… Pues muy probablemente el listillo de Chrome navegue por detrás para dar la impresión posteriormente de que las páginas cargan más rápido… pero ¿Esto da un poco de miedo no? y más si yo sé que mi web socket en el cliente se inicializa y se ejecuta en el momento en que la página ha sido totalmente cargada, o sea, en el ready.

Probé con IE10 y no pasa. No he probado con más browsers.

Salu2

Repository Pattern para ApplicationData en Windows 8

Con la llegada de Windows 8 y sus aplicaciones para el Store, muchas veces nos toca lidiar con datos almacenados en local.

La idea de este post es implementar el patrón repositorio para independizar nuestras aplicaciones del trabajo con los distintos tipos de almacenamientos en local que existen en Windows 8.

Para profundizar en este patrón puedes echar un ojo a este enlace de Martin Fowler: http://martinfowler.com/eaaCatalog/repository.html

El objetivo

– Evitar código duplicado
– Mejor gestión de errores (código centralizado)
– Menos dependencia de nuestras reglas de negocio a la persistencia
– Posibilidad de centralizar políticas relacionadas con datos como el almacenamiento en caché o Lazy load.
– Posibilidad de “testear” la lógica de negocio de forma aislada a la persistencia

Empezamos creándonos una clase abstracta que nos permita de forma genérica trabajar con cualquier tipo de datos. La clase incluirá los métodos más generales para interactuar con el almacenamiento.

Constructores

Nuestra clase genérica incluye dos constructores, uno que por defecto usará el LocalFolder y otro que nos permitirá especificar el lugar de almacenamiento.

protected Repository(string fileName) : this(fileName, StorageType.Local)
{
}

protected Repository(string fileName, StorageType storageType)
{
   _fileName = fileName.EndsWith(".json") ? fileName : string.Format("{0}.json", fileName);

   // set the storage folder
   switch (storageType)
   {
      case StorageType.Local:
         _storageFolder = _appData.LocalFolder;

         break;
      case StorageType.Temporary:
         _storageFolder = _appData.TemporaryFolder;

         break;
      case StorageType.Roaming:
         _storageFolder = _appData.RoamingFolder;

         break;
      default: throw new Exception(String.Format("Unknown StorageType: {0}", storageType));
   }
}

El parámetro fileName nos sirve para especificar un nombre de archivo para nuestros datos. El archivo será identificado siempre por la extensión json y podemos decidir pasar el parámetro con o sin ella, en cualquier caso el constructor se encargará de realizar el chequeo necesario.

El parámetro storageType es un enumerado que incluye los distintos tipos de almacenamiento.

public enum StorageType
{
   Local,
   Temporary,
   Roaming
}

Dependiendo de este parámetro, el constructor inicializa  el StorageFolder a usar por nuestro repositorio.

Los métodos

/// <summary>
/// Delete a file asynchronously
/// </summary>
public async void DeleteAllAsync()
{
   var file = await GetFileIfExistsAsync(_fileName);
   if (file != null) await file.DeleteAsync();
}

Este método nos permite eliminar todos los datos almacenados. La operación se realiza de forma asíncrona y se resume a eliminar el archivo donde se encuentran almacenados nuestros datos.

El método GetFileIfExists nos retorna de forma asíncrona un StorageFile si el archivo existe, de lo contrario retorna nulo.

/// <summary>
/// At the moment the only way to check if a file exists to catch an exception... 
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private async Task<StorageFile> GetFileIfExistsAsync(string fileName)
{
   try
   {
      return await _storageFolder.GetFileAsync(fileName);
   }
   catch
   {
      return null;
   }
}

La única forma que tenemos de saber si un archivo existe es capturando el error. La razón que Microsoft nos da para no contar con un File.Exists en el API es que el estado del archivo puede cambiar entre que nosotros preguntamos si existe y realizamos alguna operación. Según Microsoft, si contáramos con un File.Exists, igualmente tendríamos que capturar posibles errores cuando trabajamos con el archivo.

/// <summary>
/// Persist data to StorageFolder
/// </summary>
public virtual void Flush()
{
   SaveAsync(Data.Value);
}

El método Flush usa Data.Value para indicar los datos a persistir. Esto no es más que el lugar en memoria donde está almacenado nuestro objeto.

protected Lazy<T> Data;

El uso de Lazy<T> nos permite acceder a StorageFolder en el momento en que se necesiten los datos  por primera vez.

Los datos de memoria se envían al StorageFolder que seleccionemos llamando a un método interno de nuestro repositorio que realiza la persistencia de forma asíncrona.

/// <summary>
/// Saves a serialized object to storage asynchronously
/// </summary>
/// <param name="data"></param>
protected async void SaveAsync(T data)
{
   if (data == null) return;

   var file = await _storageFolder.CreateFileAsync(_fileName, CollisionOption);
   await FileIO.WriteTextAsync(file, Serialize(data).Result);
}

El método interno SaveAsync crea nuestro archivo si este no existe, de lo contrario lo re-escribe.  Estamos usando ReplaceExisting como política de Colisión, de cualquier forma, esta  variable es protegida en nuestra clase base, así que puede ser cambiada por las clases que heredan.

protected CreationCollisionOption CollisionOption = CreationCollisionOption.ReplaceExisting;

De la misma manera que guardamos en el StorageFolder, también necesitamos leer. El siguiente método nos permite recuperar un objeto de forma asíncrona.

/// <summary>
/// Load a object from storage asynchronously
/// </summary>
/// <returns></returns>
protected async Task<T> LoadAsync()
{
   try
   {
      var file = await _storageFolder.GetFileAsync(_fileName);
      var data = await FileIO.ReadTextAsync(file);

      return await Deserialize(data);
   }
   catch (FileNotFoundException)
   {
      //file not existing is perfectly valid so simply return the default 
      return default(T);
   }
}

Tanto para leer, como para escribir datos en nuestro repositorio, se usan métodos que se encargan del trabajo de serialización del objeto.

Como cada cual tiene su propio mecanismo para serializar, estos métodos son declarados como abstractos dentro de nuestra clase base, de esta forma, podemos indicar en cada clase que herede, cual será la manera en que se serializarán los objetos, incluso, pudiéramos tener dentro de la misma aplicación, objetos que se persistan usando mecanismos de serialización totalmente distintos.

protected abstract Task<string> Serialize(T data);
protected abstract Task<T> Deserialize(string data);

He dejado para el final una propiedad que nos retorna nuestro objeto desde el StorageFolder o de memoria según sea el caso.

/// <summary>
/// Return T
/// </summary>
public virtual T All
{
   get { return Data.Value; }
}

Teniendo en cuenta que nuestro Repositorio puede valer para almacenar un simple objeto o una lista de objetos, tener una propiedad pública que nos retorne “todo” no es una muy buena práctica. De cualquier forma esto no viene a sustituir grandes almacenes de datos, ya que para eso tenemos bases de datos locales como SQLLite, sino que está pensado para pequeños datos. Es por esto que me tomo la libertad de incluir una “mala” práctica en mi código.

Nuestra clase base está lista, vamos a ver cómo usarla.

Para la implementación, voy a usar Newtonsoft.Json para la serialización de los objetos. Las clases a utilizar con los repositorios serán una simple y otra una lista, para poder ver las dos formas de utilizar nuestro repositorio.

public class Account
{
   [JsonProperty]
   public string Name { get; set; }
}
public class Family : List<Person>
{
   [JsonProperty]
   public IList<Account> Itenms { get; set; }
}

public class Person
{
   [JsonProperty]
   public Guid Id { get; set; }

   [JsonProperty]
   public string Name { get; set; }

   public bool IsTransient
   {
      get { return Id == Guid.Empty; }
   }
}

Nuestro repositorio siempre trabaja con un objeto, por lo que la única diferencia entre guardar un objeto simple o una lista, no es otra que usar uno o lo otro.

En el ejemplo crearemos un repositorio para Account y otro para Family que es una lista de Person.

Vamos a ver el repositorio de Family:

    public class RepositoryFamily : Repository<Family>, IRepositoryFamily
    {
        public RepositoryFamily(): base("Family")
        {
            CollisionOption = CreationCollisionOption.OpenIfExists;
            Data = new Lazy<Family>(() => LoadAsync().Result ?? new Family(), true);
        }

        public async Task<Person> Get(Guid id)
        {
            return await Task.Factory.StartNew(() => All.Single(p => p.Id == id));
        }

        public void Save(Person person)
        {
            if (person.IsTransient)
            {
                person.Id = IdentityGenerator.NewSequentialGuid();
                Data.Value.Add(person);

                return;
            }

            var idx = Data.Value.FindIndex(a => a.Id == person.Id);
            Data.Value[idx] = person;
        }

        protected override Task<string> Serialize(Family data)
        {
            return JsonConvert.SerializeObjectAsync(data);
        }

        protected override Task<Family> Deserialize(string data)
        {
            return JsonConvert.DeserializeObjectAsync<Family>(data);
        }
    }

Como se ve, implementamos los métodos abstractos del repositorio para serializar y ya solo nos queda ir implementando los métodos que necesitemos según el tipo de datos que estemos trabajando.

Para el ejemplo, tengo el método Save que adiciona una persona en la lista si no existe, o de lo contrario, lo actualiza.

Cuando deseemos guardar una nueva persona en nuestro repositorio, el código a utilizar sería así:

private void SaveFamilyNameCommand(string name)
{
   _familySrv.Save(new Person { Name = name});
   _familySrv.Flush();

   Family = new ObservableCollection<Person>(_familySrv.All);
   RaisePropertyChanged(()=> Family);
}

La aplicación que les dejo de ejemplo, en la vista principal tiene dos TextBox, uno para que escriba su nombre y otro para que adicione los nombres de su familia.

screenshot_10072012_135829

Después de escribir su nombre y guardar y después de entrar nombres de sus familiares, puede cerrar la aplicación y volverla a abrir para ver cómo los datos se persisten.

screenshot_10072012_135936

El ejemplo requiere MVVM Light y Newtonsoft.json. Source

Salu2

[IT] Outlook.com con dominio propio

Hola,

Hace unos días q llevo intentando migrar a Outlook.com para probar que tal va.

He leído algunos POST sobre cómo conectar GMAIL a Outlook y así estar al día sobre lo que por allí recibimos desde una única interfaz. Si aún no sabes cómo hacerlo, puedes  ver este post de Pilar con video incluido.

El problema que algunos nos encontramos es que en todos los casos se usa nuestra dirección de Outlook como dirección de re-envío. Para los que usamos cuentas personales (dominios propios: odelvalle.com) para acceder a live, hacer esto  implica re-enviar todo el tráfico de nuestra cuenta GMail a nuestro servidor de correo.

Para evitar esto, intenté cambiar mi cuenta outlook pero me avisó que perdería la conexión de todos los dispositivos asociados a esa cuenta live (malo malo). Busqué si se podía crear una nueva cuenta pero eso implicaría tener 2 accesos a live, una con mi correo personal y la otra con la nueva cuenta outlook (esto tampoco me convence)

Dedicando un ratico cada mañana a buscar posibles soluciones, hoy encuentro una: :

Untitled

Crear un alias en outlook.com es la manera que tenemos de unir/asociar varias direcciones de correo electrónico a una sola. 

Untitled1

Al crear el Alias, Outlook.com te enviará un correo de verificación a tu cuenta personal (live) para asegurarse que el Alias está correctamente asociado.

Untitled2

y ya estamos listos. Podemos seguir los pasos que nos cuenta Pilar en su post y utilizar el alias de outlook como dirección de re-envío, de esta forma los correos de GMAIL no pasarán por nuestro pequeño e indefenso servidor e irán directamente al grande de Outlook.com. Sonrisa

Salu2

POO–Responsabilidades

“Hay una diferencia entre programar orientado a objetos y pensar orientado a objetos”

CNX-B4WDebatiendo hoy en el trabajo sobre la funcionalidad que debería tener una toolsbox, salió uno de esos temas que me encantan. ¿Dónde debe estar el código asociado a un clic de un botón?

Responsabilidades

Mucho más allá de si la pregunta se responde aplicando un Chain of Responsibility Pattern, dentro se esconde uno de los pilares de la POO, la Especialización. Los objetos mientras mayor sea su especialización, mejor podremos definir su comportamiento.

¿Qué quiere decir esto? Pues que la responsabilidad de cada objeto debe ser solo, la que permita cumplir los objetivos por el cual fue creado.

Un avión vuela (por suerte). Nosotros desde fuera vemos un conjunto, pero dentro del avión hay miles de objetos que tienen una responsabilidad específica y que entre todos, hace que el avión vuele. Creo que excepto en las teles de la antigua URSS (le quitabas piezas y seguían funcionando), todo objeto tiene una responsabilidad que permite lograr una funcionalidad superior.

¿Que es una toolsbox? pues un panel de botones y nada más. Cuando compramos un panel de botones este no incluye para qué se usa cada botón o qué hace cada botón. Si compramos un interruptor eléctrico, este por si solo no apaga ni enciende la luz, incluso, puede llegar a realizar funciones explosivas si conectas incorrectamente los cables (que me pregunten a mi con 11 años la que lié).

Nuestra toolsbox, tiene botones (como casi todas) y el objetivo que cumplirá cada botón debería ser independiente a la misma. Un botón “dentro de la toolsbox” tiene estados cuyos cambios son notificados al exterior para quien quiera hacer algo que lo haga.

Lo mismo pasa con nuestro avión, mueves los mandos de vuelo y giras, esto no ocurre porque las aletas y el mando sean un único e inseparable objeto, sino porque el mando cambia de estado y notifica a todo aquel que pueda estar interesado para que haga algo. Las aletas y seguramente muchos objetos más dentro de un avión, están escuchando continuamente para saber si los mandos de vuelo han cambiado de posición(estado).

Vean que para definir cual debe ser la responsabilidad de mi  toolsbox, me he basado en todo momento en ejemplos de la vida real.

En el evento que di sobre POO en SecondNug (aquí tenéis los apuntes) cuando se analizaba la crisis del software, se definió como objetivo de la programación orienta a objetos el acercamiento del ordenador al problema y no del problema al ordenador, lo cual significa que debemos intentar en todo momento modelar los problemas existentes en la vida real analizándolo como lo que son, cosas que ocurren en la realidad. Esto era y seguramente aún es, el paradigma de la POO.

El otro día leía un artículo de Eduard sobre knockout y había una línea de texto que decía: “el código javascript es totalmente ignorante del DOM y trabaja tan solo con el viewmodel. Separación de responsabilidades.” ¡Atentos! que en este artículo se habla de separar la responsabilidad entre el HTML y el Javascript… (si digo yo esto en una entrevista de trabajo hace unos años, ya me dirán ustedes que hubieran pensado de mi)

Seguramente hoy por hoy aún queda mucho por hacer, pero da gusto como cada vez más intentamos llevar a la más mínima expresión la separación de responsabilidades. Mi opinión es que mientras menor sea la responsabilidad de un objeto, siempre que cumpla su objetivo, mejor y más fácil será de mantener.

Por cierto, para no dejarles sin saber, la toolsbox terminó con N botones que no saben lo que hacen pero que notifican a quien pueda interesar los estados de onBeforeClick y onClick. (espero no ser yo quien tenga que conectarla) Sonrisa

Salu2

Mensajes de browser a browser (Web Socket)

ws_tornadoHe estado trabajando últimamente en un proyecto en el que necesitaba comunicación entre instancias distintas de browsers en tiempos lo más real posible.

La solución se desprende, Web Socket con HTML5 Sonrisa

La lógica que necesitamos en el servidor es simple, transmitir un mensaje que viene de un cliente, al resto de los clientes conectados.

En la parte del servidor quiero la menor lógica posible, así podré reutilizarlo en distintos proyectos. Los mensajes van de clientes a clientes, por lo que la responsabilidad del servidor en este caso debe ser solamente la de comunicación.

Para implementar el servidor he usado Fleck, un Web Socket que ya existe para NET y el cual recomiendo muchísimo, un código claro y fácil de entender si te pica la curiosidad y quieres conocer internamente cómo funciona.

Server

De momento vamos a crear una aplicación de consola para hospedar a nuestro Socket Server.

class Program
{
    static void Main()
    {
        FleckLog.Level = LogLevel.Debug;

        var socketManager = new MessagesWebSocket();
        socketManager.Start();

        Console.ReadLine();

        socketManager.Close();
    }
}

La clase MessagesWebSocket tendría:

class MessagesWebSocket
{
    private readonly List<IWebSocketConnection> _allSockets;
    private readonly WebSocketServer _server;


    public MessagesWebSocket()
    {
        _allSockets = new List<IWebSocketConnection>();
        _server = new WebSocketServer(ConfigurationManager.AppSettings["socketServer"]);
    }

    public void Start()
    {
        _server.Start(socket =>
        {
            socket.OnOpen = () =>
            {
                Console.WriteLine("Open client connection!");
                _allSockets.Add(socket);
            };

            socket.OnClose = () => _allSockets.Remove(socket);
            socket.OnMessage = message => _allSockets.Where(s=> s != socket).ToList().ForEach(s => s.Send(message));
        });
    }

    public void Close()
    {
        _allSockets.ForEach(s => s.Close());
        _server.ListenerSocket.Close();
    }
}

Si has trabajado con Socket verás que no hay mucha diferencia a lo que se hacía hasta ahora, incluso, la clase WebSocketServer de Fleck usa internamente System.Net.Sockets.

Nuestra clase MessagesWebSocket tiene dos métodos, Start & Stop.

Start nos permite abrir la conexión y quedarnos a la escucha de cualquier petición de conexión de algún cliente. Cuando un cliente previamente conectado envía un mensaje al servidor, este simplemente toma el mensaje tal cual y lo envía al resto de clientes conectados.

El servidor no interviene en absoluto en la estructura del mensaje que se envía, justamente lo que necesitamos. Entender los mensajes que se envían los clientes será siempre responsabilidad de ellos.

Client

Si hablamos de clientes WEB, la moda en comunicación se llama JSON! Sonrisa Así que vamos a hacer que este sea el formato que usen los mensajes enviados entre clientes.

Para que todo el tema de web socket y json nos quede fuera de la lógica de cualquier página o proyecto, vamos a encapsular toda la funcionalidad dentro de un objeto en Javascript que nos permita enviar y recibir mensajes sin importarnos cómo.

var WebSocketHelper = function (server, onMessage, onError)
{
    var w = window;
    var connection;

    var reciveData = onMessage || false;
    var error = onError || false;

    // if user is running mozilla then use it's built-in WebSocket
    w.WebSocket = w.WebSocket || w.MozWebSocket;

    // open connection
    try
    {
        connection = new w.WebSocket(server);
    }
    catch (connErr)
    {
        if (error) error("Open connection error: " + connErr);
        return;
    }

    // only for debug propose
    connection.onopen = function ()
    {
        //alert('Connected.');
    };

    connection.onmessage = function (d)
    {
        var result = jQuery.parseJSON(d.data);
        if (reciveData) reciveData(result);

        return false;
    };

    connection.onerror = function (wsErr)
    {
        if (error) error("Connection error: " + wsErr);
        connection = null;
    };

    this.SendCommand = function (obj)
    {
        try
        {
            var jsonString = JSON.stringify(obj);
            connection.send(jsonString);
        }
        catch (sendErr)
        {
            if (error) error("Send message error: " + sendErr);
        }
    };
};

Vamos por parte.

1- Al objeto WebSocketHelper le pasamos tres parámetros: la dirección del servidor, una función (opcional) que se ejecutará cuando nos llegue un nuevo mensaje y otra función (también opcional) que se ejecutará si encontramos algún error.

2- Instanciamos un nuevo objeto WebSocket, y aquí entramos en las diferencias entre browsers de toda la vida. Firefox tiene un objeto MozWebSocket mientras Chrome e Internet Explorer (v10) usan WebSocket.

3- Luego de instanciado el socket, intentamos abrir la conexión con el servidor, si todo sale bien, estamos listos para enviar y recibir datos mediante el socket.

4- El evento onmessage es quien me permite capturar los mensajes que llegan desde el servidor. La función asociada a este evento toma el mensaje recibido y lo transforma a un objeto javascript usando jQuery.parseJSON. Al tener la información recibida como objeto javscript, se ejecuta la función que hemos pasado al WebSocketHelper pasando como parámetro el objeto recibido.

5- Para enviar un objeto al servidor el proceso es parecido. Se usa la función pública SendCommand y se pasa como parámetros el objeto a enviar. Esta función internamente convierte el objeto en string y lo envía mediante el socket al servidor.

¿Cómo funciona esto desde una página?

Primero que todo hay que llegar a un acuerdo entre clientes, podemos enviar cualquier objeto javascript mediante el servidor pero es necesario que los clientes sepan de que va el asunto, porque de lo contrario sería como pedir una cerveza y que de pronto te lleguen melones, quesos, tomates, gambas y sandias ( y lo peor es que intentes algo porque creas que son cervezas).

En mi caso he usado una estructura de objetos muy simple. Internamente cada objeto que envío tiene una propiedad llamada command que define el tipo de mensaje que es.

var commands = { stop: "stop", start: "start", game: "game", reset: "reset", gameover: "gameover" };

Inicializando el socket server y recibiendo datos desde el servidor:

var socket = new WebSocketHelper("ws://192.168.100.64:8181", function (cmd)
{
    switch (cmd.command)
    {
        case commands.gameover:

            // GAME Over
            break;

        case commands.start:
            
            alert("Welcome {0}. Are you ready?".format(cmd.player));
            break;

        default: throw new Error("Invalid Command on socket server.");

    }
});

Enviando mensajes:

socket.SendCommand(
{
    command: commands.start,
    player: 'Pepe el loco',
    device: 1,
    language: 'es'
});

y con esto ya tenemos una comunicación simple de browser a browser.

Más adelante veremos otro ejemplo en el que vamos a darle más responsabilidad al SocketServer enviando comandos recibidos desde una Kinect a clientes Web y ya de paso, convertiremos nuestro WebSocket en un servicio Windows.

Salu2

Navigator para WP7 en MVVM

Otro tema que estaba pendiente…

Cuando empecé a estudiar y testear cosas de WP7 con MVVM, una de los detalles que más me molestaban era tener que navegar entre páginas usando el code behind.

Es verdad que desde el ViewModel puedes tener acceso al NavigationService, pero esto sería una muy mala práctica de cara a los test unitarios. Por otra parte, desde dónde puedo capturar los parámetros pasados a una vista es siempre el método OnNavigatedTo que tenemos en el Code Behind.

Una tarde escuchando una charla de Josue sobre WP7, comentó que se encontraba desarrollando una aplicación llamada WPControla. Soy de los que piensa que una de las mejores maneras de tomar buenas prácticas en los desarrollos es mirar mucho código, cualquiera, no importa de quien sea porque siempre te ayudan a comparar y sacar conclusiones sobre lo que se debe o no hacer. 

En la propia charla le pregunté a Josue si podríamos descargarnos el código de la aplicación y como siempre, nos dio acceso al repositorio. Winking smile

Mirando el código de esta aplicación descubrí algo que me llamó mucho la atención, dentro del namespace WPControla.Client.Services había una clase llamada NavigationService. Me imaginé que esta clase, al implementar una interfaz sería una solución a lo que tanto me había molestado hasta el momento, poder navegar entre Views desde el ViewModel sin afectar los test.

Me costó entender cómo funcionaba porque en el repo no está toda la funcionalidad aún implementada, así que le pregunté directamente a Josue si esto era lo que me imaginaba y cómo había pensado en resolver esto, su respuesta no se hizo esperar. Gracias Josue! Smile

Con permiso del Master, vamos a intentar explicar la solución que implementa  WPControla.

Todo parte de una clase llamada NavController en la cual se empieza definiendo un singleton para el acceso a una única instancia. También contamos con un Dictionary que nos permite registrar y referenciar las vistas mediante “alias”.

registeredViews.Add("Start", new Uri(@"/MainPage.xaml", UriKind.Relative));

En mi caso, cambié el Dictionary utilizado:

static Dictionary<String, Uri> registeredViews = new Dictionary<String, Uri>();

por:

private static readonly Dictionary<Pages, Uri> _registeredViews = new Dictionary<Pages, Uri>();

Pages es un enumerado, esto no implica ninguna mejora a la solución planteada por Josue, más bien es un gusto personal, no me gusta trabajar con string porque soy muy despistado Sad smile y siempre los escribo mal, así que me ahorro errores de ejecución usando enumerados.

La clase define  tres sobrecargas sobre el método NavigateTo. Una sobrecarga nos permite navegar a una vista sin pasar parámetros, en la segunda, podemos incorporar parámetros pasados por QueryString y en la tercera nos vamos a detener:

public void NavigateTo(String navigationTarget, Action<NavigationEventArgs> onNavigated)

Esta sobrecarga incluye un Action<NavigationEventArgs> como parámetro, el objetivo es poder tomar una acción en el momento en que se navegue de una vista a otra. Internamente la clase navController captura el evento Navigated de PhoneApplicationFrame y cuando este ocurre, ejecuta nuestra acción.

/// <summary>
/// Este evento se lanza cuando hemos navegado a una página.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void root_Navigated(object sender, NavigationEventArgs e)
{
    if (NavigationMethod != null)
    {
        NavigationMethod(e);
        NavigationMethod = null;
    }
}

Este método de la forma que está escrito, no nos permite capturar el Navigated cuando el NavigationMode es Back, o sea, cuando vamos de regreso. Para solucionarlo solo necesitamos eliminar la línea de código que asigna null al NavigationMethod y no olvidar desasignar el evento cuando regresemos, porque de lo contrario navegando hacia atrás y hacia adelante multiplicará la cantidad de veces que se ejecuta nuestra acción.

void RootNavigated(object sender, NavigationEventArgs e)
{
    if (_navigationMethod == null) return;

    _navigationMethod(e);

    if (e.NavigationMode != NavigationMode.Back) return;
    var rootFrame = (PhoneApplicationFrame)Application.Current.RootVisual;
        
    rootFrame.Navigated -= RootNavigated;
}

Otra particularidad de esta sobrecarga es que mediante el parámetro NavigationEventArgs tenemos acceso a la View que estamos navegando mediante la propiedad Content, a su vez, mediante la View tenemos acceso al DataContext que en una arquitectura MVVM sería el ViewModel. Esta estructura pudiera ser utilizada para inicializar objetos complejos cuando navegamos de una vista a otra (luego veremos un ejemplo).

Ya que estamos creando métodos de navegación, adicioné a esta clase un método que nos permita hacer Back por código.

public void NavigateToBack()
{
    var rootFrame = Application.Current.RootVisual as PhoneApplicationFrame;
    if (rootFrame == null || !rootFrame.CanGoBack) return;

    rootFrame.GoBack();
}

La magia para que todo esto se integre con nuestros ViewModels llega ahora:

Definimos una interfaz con los distintos métodos para la navegación que necesitamos en nuestra aplicación, hacemos que un servicio implemente dicha interfaz y lo usamos en el constructor de los distintos ViewModels.

Un servicio de navegación que utilice NavController quedaría como el siguiente:

public interface INavigatorService
{
    void GotoMvvmView1();
    void GotoMvvmView1(DataItem param);

    void GoBack();
}

public class NavigatorService : INavigatorService
{
    public void GotoMvvmView1()
    {
        NavController.Current.NavigateTo(NavController.Pages.MvvmView1);
    }

    public void GotoMvvmView1(DataItem param)
    {
        NavController.Current.NavigateTo(NavController.Pages.MvvmView1, 
            args =>
            {
                if (args.NavigationMode != NavigationMode.New) return;

                var view1Model = ((FrameworkElement) (args.Content)).DataContext as View1ViewModel;
                if (view1Model != null) view1Model.Initialize(param);
            });
    }

    public void GoBack()
    {
        NavController.Current.NavigateToBack();
    }
}

Observen como estamos ejecutando una acción en el momento en que llegamos a la vista a la que deseamos navegar. Esta acción accede al ViewModel e inicializa parámetros necesarios con los datos que se pasan al método GotoMvvmView1.

A mi este mecanismo no me gusta  (cuestión personal), no sé si será buena o mala práctica, pero me cuesta tener que acceder a métodos del ViewModel desde este punto.

Para solucionar este problema he incorporado a la clase NavController un Dicctionary para pasar datos entre vistas.

/// <summary>
/// Navigation Parameters 
/// </summary>
public static IDictionary<string, object> Parameters { get; set; }

Como NavNavigator es independiente de nuestros ViewModels mediante una interfaz, tenemos que adicionar a la misma la utilización del Dictionary. La interfaz vista anteriormente ahora nos quedaría así:

public interface INavigatorService
{
    IDictionary<string, object> Parameters { get; set; }

    void GotoMvvmView1();
    void GotoMvvmView1(DataItem param);

    void GoBack();
}

y su implementación sería…

public class NavigatorService : INavigatorService
{
    public IDictionary<string, object> Parameters
    {
        get { return NavController.Parameters; }
        set { NavController.Parameters = value; }
    }

    public void GotoMvvmView1()
    {
        NavController.Current.NavigateTo(NavController.Pages.MvvmView1);
    }

    public void GotoMvvmView1(DataItem param)
    {
        NavController.Current.NavigateTo(NavController.Pages.MvvmView1, 
            args =>
            {
                if (args.NavigationMode == NavigationMode.Back) return;

                NavController.Parameters = new Dictionary<string, object> { { "item", param} };
            });
    }

    public void GoBack()
    {
        NavController.Current.NavigateToBack();
    }
}

Después de tener esto solo nos queda pasar el servicio de navegación en el constructor de nuestros ViewModels y acceder a los distintos métodos para navegar.

/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IDataService dataService, INavigatorService navigator)
private void GotoView1Command()
{
    _navigator.GotoMvvmView1(_item);
}

Quizás pienses que a esta altura, cuando ya WP7 solo tendrá una próxima actualización y las cosas cambiarán de cara a WP8 y a la nueva interfaz de W8 (antes Metro), ya no tienen mucho sentido. Puedes echarle una ojeada a este post sobre W8 del propio Josue y seguramente habrá cosas que te resulten familiar. Winking smile

Salu2

Código del ejemplo