Quantcast

comments edit

Histoire de changer un peu mon quotidien, j’ai jeté un oeil à Xamarin. Premiere épreuve, faire reconnaitre mon HTC One X par le debugger.

Dans l’ordre :

; HTC One X
%SingleAdbInterface% = USB_Install, USB\VID_0BB4&PID_0CED
%CompositeAdbInterface% = USB_Install, USB\VID_0BB4&PID_0CED&MI_01
  • Exécuter la ligne de commande shutdown /r /o
  • Une fois le rédémarrage effectué, aller dans Dépannage > Avancé > Options de démarrage > Rédémarrer > F7
  • Connecter le téléphone
  • Activer le débuggage USB dans le téléphone
  • Executer devmgmt.msc
  • Clic droit sur Android phone, puis Mettre à jour le pilote > Rechercher un pilote sur mon ordinateur > Choisir parmi une liste de pilotes... > Disque fourni
  • Indiquer le chemin vers android_winusb.inf
  • Accepter l’avertissement de sécurité

Exécuter adb devices pour vérifier la présence du téléphone :

C:\adt-bundle-windows-x86_64-20131030\sdk\platform-tools>adb devices
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
List of devices attached
HTxxxxxxxxxx    device

Facile, surtout grâce a un mix des liens suivants :

comments edit

Un petit peu d’archéologie

  • 1996 : ASP
  • 2002 : ASP.NET (Visual Studio 2003)
  • 2005 : ASP.NET 2.0 (Visual Studio 2005
  • 2007 : ASP.NET 3.5 (Visual Studio 2008)
  • 2009 : ASP.NET MVC 1
  • 2010 : ASP.NET MVC 2
  • 2011 : ASP.NET MVC 3
  • 2012 : ASP.NET 4.5 (Visual Studio 2012)
  • 2012 : ASP.NET MVC 4 + Web API 1
  • 2013 : ASP.NET MVC 5 + Web API 2

Le point interessant a noter, est que depuis 1996, le nombre d’utilisateurs d’internet a radicalement augmenté :

Croissance des utilisateurs d'internet, par 100 habitants Source : Wikipedia

De ce fait, les frameworks permettant de développer les applications ont donc du suivre un rythme soutenu. Jusqu’en 2009, Microsoft mettait a jour son framework ASP.NET en même temps que Visual Studio, l’outil de développement. ASP.NET MVC change la donne, car il est distribué en tant que complément, et du coup ne subit par les contraintes temporelles de Visual Studio. Depuis sa sortie, le framework a été mis à jour à raison de une fois par an.

En meme temps que le nombre d’utilisateurs d’application web augmente, leurs attentes envers ses applications augmentent également : interfaces plus riches, plus de réactivité…

Oui, et ?

L’avènement des framework tels ASP.NET ont permi de simplifier une bonne partie du code pour développer des applications de plus en plus dynamiques, mais dans une certaine limite, tant d’un point de vue de maintenabilité que de performance.

Traditionnelement, les interactions navigateur serveur suivent deux “canaux” :

  • un flux html a chaque changement de page
  • un ou plusieurs flux AJAX.

Avec ASP.NET, les services fournissant les données a des appels ajax peuvent être implémentés de différentes manières :

  • services asmx / webmethods : obsolete
  • IHttpHandlers : implémentation “manuelle” fastidieuse
  • Services WCF : implémentation complexe dans le cas de services non SOA

ASP.NET MVC a apporté deux élements clés pour simplifier ce probleme

  • le routing, pour découpler facilement la localisation du fichier source représentant le service, et sont adresse http
  • le ModelbBinding, pour simplifier la sérialisation/désérialisation des données dans le flux HTTP

Et Web API dans tout ca ?

Pendant ce temps la, d’autres patterns et habitudes commencaient a prendre de l’ampleur…

L’ouverture des données et des API des applications web, donnant naissance aux premiers mashups : mix de données issues de différents services pour en fournir un nouveau, comme par exemple http://www.housingmaps.com/, qui reprend les annonces immobilieres de Craigslist, et les places sur une carte Google maps. Et c’etait en 2005 ! REpresentational State Transfer (ou REST), définit une sémantique pour exposer des services sur le protocole HTTP. Enfin, le templating client a également pris de l’essor, toujours pour améliorer la réactivité de nos chères applications.

Du coup, certains utilisateurs de ASP.NET MVC ont souhaité pour disposer des capacités de Routing, ModelBinding, etc, de ASP NET MVC, sans utiliser la partie templating. D’où la naissance de ASP.NET Web API.

Et concrètement, ca fait quoi ?

La suite, au prochain épisode !

comments edit

Une des grosses forces de ASP.NET Web API est sa modularité. Celle ci facilite la mise en place des principes SOLID, le S, pour Separation of Concerns, en particulier.

Pour la suite de l’article, nous allons tester un controller assez basique, dépendant d’un service injecté par le constructeur :

[RoutePrefix("api/names")]
public class NamesController : ApiController
{
	private const string PrefixRegex = "[a-zA-Z]+";
	
	private readonly IDataProvider dataProvider;

	public NamesController(IDataProvider dataProvider)
	{
		this.dataProvider = dataProvider;
	}

	[Route("{prefix}")]
	public IHttpActionResult GetNames(string prefix)
	{
		var names = this.dataProvider.GetFirstNames().Where(x => x.StartsWith(prefix));

		if (!Regex.IsMatch(prefix, PrefixRegex))
		{
			return StatusCode(HttpStatusCode.BadRequest);
		}

		if (!names.Any())
		{
			return NotFound();
		}

		return Ok(names);
	}
}

Afin de pouvoir utiliser ce controller dans Web API, il faut remplacer le DependencyResolver par défaut, par une implémentation spécifique à Windsor. Habituellement, cet enregistrement se passe dans une classe de configuration, appelée dans la méthode MvcApplication.Application_Start. Les différents composants seront crées et nettoyés à chaque requete HTTP.

public class WindsorConfig
{
	public static void Register<T>(HttpConfiguration config) where T : IScopeAccessor, new()
	{
		var container = new WindsorContainer();

		config.DependencyResolver = new WindsorResolver(container);

		// when we begin registering many components, we should use installers here
		container.Register(Component.For<IDataProvider, DataProvider>().LifestylePerWebRequest());
		container.Register(Component.For<NamesController>().LifestylePerWebRequest());
		container.Register(Component.For<ClientsController>().LifestylePerWebRequest());
	}
}

public class MvcApplication : System.Web.HttpApplication
{
	protected void Application_Start()
	{
		WebApiConfig.Register(GlobalConfiguration.Configuration);
		BundleConfig.Register(BundleTable.Bundles);
		WindsorConfig.Register(GlobalConfiguration.Configuration);

		GlobalConfiguration.Configuration.EnsureInitialized();
	}
}

Une fois cette infrastructure en place, nous pouvons appeler normalement notre API REST.

Supposons que nous souhaitions maintenant lancer des tests d’intégration, afin de valider le bon fonctionnement de cette API. Il est possible d’héberger une application WebAPI dans un process OWIN, sans serveur IIS. Ceci devient extrêmement pratique dans le cadre de tests automatisés.

Nous pouvons donc écrire un premier test :

[TestClass]
public class NamesControllerTest : ControllerTestBase
{
	protected static readonly string baseAddress = "http://localhost:9000/";
	protected static IDisposable app;

	/// <summary>
	/// Start the self hosted server once per assembly
	/// </summary>
	/// <param name="context"></param>
	[AssemblyInitialize]
	public static void AssemblyInitialize(TestContext context)
	{
		app = WebApp.Start<Startup>(baseAddress);
	}

	/// <summary>
	/// Do not forget to clean up !
	/// </summary>
	[AssemblyCleanup]
	public static void AssemblyCleanup()
	{
		if (app != null)
		{
			app.Dispose();
		}
	}
	
	[TestMethod]
	public void Valid_prefix_must_return_OK()
	{
		using (var client = new HttpClient())
		{
			var response = client.GetAsync("http://localhost:9000/api/names/A").Result;

			Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
		}
	}
}

public class Startup
{
	public void Configuration(IAppBuilder appBuilder)
	{
		var config = new HttpConfiguration();

		var container = WindsorConfig.Register<LifetimeScopeAccessor>(config);
		WebApiConfig.Register(config);

		appBuilder.Use<OwinRequestLifeTimeManager>(container);
		appBuilder.UseWebApi(config);
		
		config.EnsureInitialized();
	}
}

Le point interessant est la classe Startup : celle ci agira de manière similaire au Global.asax, dans les deux cas nous initialisons WebApi et Windsor. Les différences étant :

  • la création de l’objet HttpConfiguration est à notre charge dans le cas d’un hébergement OWIN Self-hosted
  • le IScopeAccessor est différent, le serveur OWIN Self-hosted ne disposant pas de la notion d’HttpModule

Pour pouvoir tout de même limiter la durée de vie des composants enregistrés dans Windsor, il a fallu implémenter un middleware OWIN :

/// <remarks>
/// Inspired from : https://github.com/castleproject/Windsor/blob/master/src/Castle.Windsor/MicroKernel/Lifestyle/PerWebRequestLifestyleModule.cs
/// </remarks>
public class OwinRequestLifeTimeManager : OwinMiddleware
{
	private readonly IWindsorContainer container;

	public OwinRequestLifeTimeManager(OwinMiddleware next, IWindsorContainer container)
		: base(next)
	{
		this.container = container;
	}

	public override Task Invoke(IOwinContext context)
	{
		using (new CallContextLifetimeScope(container))
		{
			// subsequent middlewares are executed inside this scope
			return Next.Invoke(context);
		}
	}
}

Ce middleware OWIN encapsule l’execution des middleware suivants (dont Web API) dans un scope spécifique, afin de “simuler” le comportement du PerWebRequestLifestyle.

Du coup maintenant nous pouvons exécuter de jolis tests d’intégration automatisés, sans passer par IIS.

Le code source est disponible sur github

comments edit

Avant de rentrer dans le vif du sujet, petit rappel sur le fonctionnement du cache du navigateur.

Lorsque le navigateur demande une ressource (index.html par exemple) au serveur, celui ci lui renvoie plusieurs éléments :

  • un statut HTTP (200 SUCCESS ici)
  • le contenu du fichier index.html
  • un ensemble d’en-têtes http

Parmi ces en-têtes, on retrouvera (en fonction de la configuration du serveur) :

  • un ETAG, qui est un checksum calculé selon le contenu renvoyé au navigateur
  • une date d’expiration, qui indique au navigateur la durée de vie de la ressource demandée

Il est à noter que les valeurs dans l’en-tête sont purement prescriptives, charge au navigateur de les respecter.

Lorsque le navigateur refait une requête au serveur pour le fichier index.html, il adjoindra également des en-têtes à sa requête. L’en-tête ETAG permettra de répondre au navigateur par un statut 304 NOT MODIFIED, dans le cas ou le fichier n’aurait pas changé.

L’en-tête date d’expiration permet au navigateur d’éviter d’envoyer des requêtes au serveur : tant que la date d’expiration n’est pas atteinte, le navigateur utilise la copie en cache.

Les templates AngularJS sont chargés au travers du service $http, qui se base sur xmlHttpRequest, qui lui même bénéficie du cache du navigateur.

Imaginons le scénario suivant :

  • le matin a 8h, le navigateur du client A demande le fichier index.html
  • le serveur lui renvoie, avec un ETAG “ABCD”, et une date d’expiration fixée au lendemain 8h
  • lors de l’utilisation de l’application, le navigateur va se baser sur la version en cache du fichier, tant que la date d’expiration est atteinte
  • a 12h, une nouvelle version de l’application est mise en ligne

Jusqu’au lendemain 8h, le client A utilisera une version potentiellement obsolète du fichier index.html.

Pour eviter cela, je vais mettre en place un mécanisme permettant d’assurer le bon fonctionnement du cache, tout en utilisant les derniers fichiers disponibles de l’application.

Dans un premier temps, il faut fournir un numéro identifiant l’application déployée. J’ai choisi d’utiliser la date de création d’un assembly du projet Web. Pour cela, j’ai intégré une simple balise script déclarant une constante AngularJs :

<script type="text/javascript"> 
    angular.module('SampleApplication.Config', []) 
        .constant('SampleApplicationVersion', '<%: Version %>'); 
</script>

La suite de l’implémentation est aisée, grâce au système de HttpInterceptors fourni par AngularJs. Ces HttpInterceptors permettent de modifier les requêtes envoyées et reçues par le service $http.

.factory('SmartCacheInterceptor', ['$q', 'SampleApplicationVersion', function ($q, SampleApplicationVersion) { 
    return { 
        request: function (config) { 
            if (config.url.indexOf(".htm") > -1) { 
                var separator = config.url.indexOf("?") === -1 ? "?" : "&"; 
                config.url = config.url + separator + "v=" + SampleApplicationVersion; 
            } 
            return config || $q.when(config); 
        } 
    }; 
}]);

Voici les résultats dans fiddler. Les requêtes sur l’url “/” correspondent a un rafraichissement de la page du navigateur. Le serveur web utilisé est IIS Express, sans paramétrage spécifique.

Capture fiddler

Le code source est disponible sur github

comments edit

Depuis la version 1.2.0 de AngularJs, le service $resource retourne des promise lors des appels aux méthodes get, query, save… Ceci ouvre des possibilités intéressantes, notamment la mise en place rapide d’indication de chargement.

Pour ce faire, j’ai choisi d’implémenter une directive, afin de pouvoir déclarer mon Loader ainsi :

<div loader="data"> 
     
</div>

Ceci va donc orienter la déclaration de la directive, pour utiliser la transclusion et un scope isolé :

.directive('loader', ['$q', function ($q) { 
    return { 
        transclude: true, 
        templateUrl: 'app/loader/loader.html', 
        scope: { 
            source: '=loader' 
        }, 
        link: function (scope, elem, attrs) { 
             
        } 
    } 
}])

Ensuite il faut écrire la fonction link pour réagir aux évènements du promise :

.directive('loader', ['$q', function ($q) { 
    return { 
        transclude: true, 
        templateUrl: 'app/loader/loader.html', 
        scope: { 
            source: '=loader' 
        }, 
        link: function (scope, elem, attrs) { 
            scope.$watch("source", function (val) { 
                scope.status = 0; 
                val.$promise.then(function (success) { 
                    scope.status = 200; 
                }, function (err) { 
                    scope.status = err.status; 
                }); 
            }); 
        } 
    } 
}])

La fonction $watch de l’objet scope permet de réagir à une assignation de la valeur en chargement; notamment lors de l’appel à une fonction de rechargement de données. Pour obtenir une référence sur l’objet promise renvoyé par $resource, il faut passer par la propriété $promise de celui-ci

Enfin, pour afficher tout ça, il nous faut un template :

<div> 
    <div ng-hide="status==200"  ng-switch="status"> 
        <div ng-switch-when="0"> 
            <span><i class="fa fa-2x fa-spin fa-spinner"></i> Loading</span> 
        </div> 
        <div ng-switch-default> 
            <span>Error from server : </span> 
        </div> 
    </div> 
    <div ng-show="status==200" ng-transclude></div> 
</div>

Le code est disponible sur github.