Windows Phone 7, Async, Extensions, Tasks, RestSharp et GeoCoordinateWatcher

windows_phone_8_logoA l’heure de Windows (Phone) 8, de l’asynchronisme, Tasks en tout genre, nous devenons de plus en plus dépendants de techniques qui peuvent rendre le développement plus simple, plus clair, plus maintenable, plus portable, plus « responsive »… La notion d’async/await n’est presque plus méconnue de personnes tant elle a abstrait la complexité qu’il pouvait y avoir pour beaucoup d’écrire des applications asynchrones. Nous ne reviendrons pas sur ces notions dans cet article (parce qu’il existe déjà beaucoup d’autres articles qui en parlent), mais nous verrons comment nous avons pu l’utiliser pour « simplifier » l’utilisation de RestSharp et du GeoCoordinateWatcher sous Windows Phone 7 (Car, oui, beaucoup continuent de développer pour WP7…).

Avant tout, faut-il ou pas continuer à développer pour Windows Phone 7 ?

C’est vrai que les ventes de Windows Phone 8 sont exceptionnelles d’après les nouvelles, beaucoup plus importantes que celles de Windows Phone 7 à la même époque. Par ailleurs, beaucoup de personnes ont renouvelé leur(s) appareil(s) vers ceux de la nouvelle plateforme, abandonnant ainsi leur premier amour. Mais, qu’en est-il de ceux qui ne pourront pas changer d’appareils et qui migreront vers la mise à jour 7.8 ? Qu’en est-il des téléphones « low-cost » qui seront équipés par défaut de Windows Phone 7.8 ?

Peu importe leur nombre (restant…), Je pense qu’ils constituent une cible à ne pas négliger.
Attention ! Il y a quand même des décisions qui feraient qu’il ne soit pas du tout possible de développer pour Windows Phone 7 (cas d’API spécifiques WP8, coût de développement limité, « être pressé », etc…), mais, quand cela est possible, il devrait être envisagé. Beaucoup de techniques permettent de pouvoir aisément maintenir du code entre différentes applications (Phone 7.8 / Phone 8 et Windows 8). Cela fera partie du cadre d’un autre article.
Quoiqu’il en soit, pour ceux qui continuent de développer pour Windows Phone 7, je vous apporte un peu de baume au cœur :-).

Pourquoi utiliser de l’Async sous Windows Phone 7 ?

Pour les raisons déjà évoquées en haut, et surtout parce que cela est rendu possible par l’ex-framework Async CTP est passée en beta. Vous pouvez lire plus d’informations à ce sujet sur le blog de la team BCL qui vous expliquera aussi comment l’installer au sein de vos projets. L’avantage d’utiliser l’Async dans Windows Phone 7, c’est aussi (et surtout) pour pouvoir augmenter la partie de code (async) portable entre vos différentes plateformes. Un seul code async pour Windows Phone 7, Windows Phone 8 et Windows 8.

Async et Restsharp

Si vous ne connaissez pas RestSharp, c’est un framework très utile dont j’ai déjà eu l’occasion de parler et qui permet de simplifier l’utilisation d’APIs REST/HTTP tout en encapsulant un mécanisme de (de)sérialisation (si vous en avez besoin) et bien d’autres fonctionnalités ! RestSharp permet actuellement de fonctionner en asynchrone mais, avec un callback qui doit être implémenté. L’avantage de l’async/await est de pouvoir travailler de façon linéaire dans votre code, les instructions les unes après les autres. Il est possible ainsi de retrouver cette façon de travailler avec RestSharp via une méthode d’extensions et les tâches et plus particulièrement en utilisant l’objet TaskCompletionSource.

Voici comment s’y prendre :

namespace Carbureco.Services
{
    using RestSharp;
    using System;
    using System.Threading.Tasks;
 
    public static class RestClientExtensions
    {
        public static Task<IRestResponse> ExecuteTaskAsync(this RestClient client, RestRequest request)
        {
            if (client == null)
                throw new NullReferenceException();
 
            var tcs = new TaskCompletionSource<IRestResponse>();
 
            client.ExecuteAsync(request, (response) =>
            {
                if (response.ErrorException != null)
                    tcs.TrySetException(response.ErrorException);
                else
                    tcs.TrySetResult(response);
            });
 
            return tcs.Task;
        }
 
        public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new()
        {
            if (client == null)
                throw new NullReferenceException();
 
            var tcs = new TaskCompletionSource<IRestResponse<T>>();
 
            client.ExecuteAsync<T>(request, response =>
            {
                if (response.ErrorException != null)
                    tcs.TrySetException(response.ErrorException);
                else
                    tcs.TrySetResult(response);
            });
 
            return tcs.Task;
        }
    }
}

En termes simples, l’objet TaskCompletionSource permet de pouvoir récupérer une Task. Ce qu’il faut savoir, c’est que la Task n’est renvoyée que quand les déclencheurs l’auront ordonné (les méthodes [Try]SetException et [Try]SetResult).

Grâce à ces méthodes d’extensions, il est maintenant possible d’utiliser RestSharp comme ceci :

var client = new RestClient("http://YourSuperWebSite");
var request = new RestRequest {
                Method = Method.GET,
                RequestFormat = DataFormat.Json,
                Resource = "YourSuperRessource"
            };
var response = await client.ExecuteTaskAsync<List<string>>(request);
//Youuhoouu, do something with response ! no more callback <3 !

Async et GeoCoordinateWatcher

Vous l’aurez donc sans aucun doute deviné, je procèderai « un peu » de la même manière pour étendre l’objet GeoCoordinateWatcher.

namespace Carbureco.Core.Helpers
{
    using System;
    using System.Collections.Generic;
    using System.Device.Location;
    using System.Threading;
    using System.Threading.Tasks;
 
    public static class GeoExtensions
    {
        public static Task<GeoCoordinate> PleaseGetCoordinatesAsync<TTaskEventArgs>(this GeoCoordinateWatcher watcher)
            where TTaskEventArgs : GeoCoordinate
        {
            var tcs = new TaskCompletionSource<GeoCoordinate>();
            EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>> positionChanged = null;
            positionChanged = (s, e) =>
            {
                var pos = e.Position.Location;
                watcher.PositionChanged -= positionChanged;
                watcher.Stop();
                tcs.SetResult(pos);
            };
            watcher.PositionChanged += positionChanged;
            watcher.Start();
 
            return tcs.Task;
        }
    }
}

Et voilà ! J’espère que vous aurez appris un peu plus au travers ce petit article. Bon développement et à très bientôt !

Nombre de vue : 142

COMMENTAIRES 2 commentaires

  1. […] A l’heure de Windows (Phone) 8, de l’asynchronisme, Tasks en tout genre, nous devenons de plus en plus dépendants de techniques qui peuvent rendre le développement plus simple, plus clair, plus maintenable, plus portable, plus « responsive »… La notion d’async/await n’est presque plus méconnue de personnes tant elle a abstrait la complexité qu’il pouvait y avoir pour beaucoup d’écrire des applications asynchrones. Nous ne reviendrons pas sur ces notions dans cet article (parce qu’il existe déjà beaucoup d’autres articles qui en parlent), mais nous verrons comment nous avons pu l’utiliser pour « simplifier » l’utilisation de RestSharp et du GeoCoordinateWatcher sous Windows Phone 7 (Car, oui, beaucoup continuent de développer pour WP7…). Je vous propose de découvrir la suite de cette article sur le blog de Soat. […]

  2. Arie Boutendraaier dit :

    Tres bon !

AJOUTER UN COMMENTAIRE