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