Intermédiaire

Kestrel et HttpPlatformHandler

ASP.NET logoDans ce billet, je vous invite à découvrir deux nouveaux projets : Kestrel et HttpPlatformHandler. Les deux sont liés à l’éco-système web de Microsoft et sont mis en application avec ASP.NET Core. Mais ce n’est pas tout, ils apportent une nouvelle approche dans l’architecture de production des applications web .NET.

Attention, cet article a été écrit à partir de la rc1 d’ASP.NET Core. Les APIs décrites ici sont encore sujettes à changement d’ici la release finale de la plate-forme.

Helios

Helios est un hôte web basé sur IIS et qui repose sur les principes d’OWIN. Il avait été annoncé par Microsoft au tout début 2014. Techniquement Helios n’est pas lié à ASP.NET Core. Il peut être utilisé avec toutes les applications compatibles OWIN et Katana. Son but est de réduire le couplage entre ASP.NET et IIS, tout en gagnant en souplesse puisqu’il est distribué au travers de Nuget. Deux ans plus tard, force est de constater que le contrat n’est pas totalement respecté… En effet, Helios a un problème, et même un problème de taille : il repose toujours sur l’assembly System.Web.

Si vous souhaitez vous intéresser un peu plus à la genèse d’Helios, je vous invite à jeter un œil ici.

Ainsi, jusqu’à la beta 7 d’ASP.NET Core, vous pouviez trouver l’inclusion d’un paquet Microsoft.AspNet.Server.IIS. Ce paquet correspond en fait à Helios. Il était utile notamment au démarrage de DNX et de la CLR en se branchant directement dans le modèle de traitement des requêtes utilisé par System.Web.

Cependant, pour tous les autres scénarios où IIS n’est pas la plateforme cible, Microsoft fournit un autre hôte, plus générique et multi-plateforme. Continuer à maintenir deux hôtes différents n’était pas viable pour les ingénieurs de Microsoft. Ils ont donc décidé d’abandonner Helios et de revoir l’approche utilisée pour cibler IIS avec une application ASP.NET Core. Cette nouvelle approche se base sur un hôte unique et deux éléments : le gestionnaire HttpPlatformHandler et le serveur web Kestrel.

HttpPlatformHandler

Le nouveau modèle tourne à présent autour d’un gestionnaire HTTP nommé HttpPlatformHandler. Ce dernier a pour but de simplement faire le pont entre IIS et un serveur HTTP, par exemple Kestrel (j’y reviendrai un peu plus tard dans ce billet).

En d’autres termes, le but de ce gestionnaire est de permettre l’hébergement par IIS d’un processus capable d’écouter le trafic HTTP sur un port spécifique. IIS va alors simplement se contenter de router le trafic entrant vers un sous-processus contrôlé par HttpPlatformHandler.

Ainsi, grâce à HttpPlatformHandler, nous sommes capables d’exécuter des applications basées sur Tomcat, Node.exe ou encore Ruby … le tout dans IIS. D’ailleurs, à la base, le gestionnaire n’est pas distribué par l’équipe ASP.NET, mais par l’équipe IIS, dans le but de faire fonctionner des applications Java sur Windows Azure.

Vous pouvez télécharger le gestionnaire ici.

La version minimale de IIS supportée est IIS 7.5. Le module est donc compatible avec les postes qui tournent au minimum sur Windows 7 ou Windows Server 2008 R2.

Une fois le gestionnaire installé, sa configuration passe par un simple fichier web.config. Notez au passage que, depuis la beta8 d’ASP.NET Core, le scaffolding de création d’un nouveau projet ASP.NET Core sous Visual Studio ajoute automatiquement un fichier web.config dans le dossier wwwroot.

Vous trouverez ci-dessous un exemple de fichier de configuration du gestionnaire pour Tomcat. Notez les éléments suivants : le nœud httpPlatform possède un attribut processPath, qui doit être renseigné par le chemin vers un .exe ou un .cmd à exécuter pour démarrer le processus du serveur. Notez également qu’il est possible de passer des arguments lors de l’exécution de ce processus, de rediriger la sortie standard vers un fichier ou encore de définir un ensemble de variables d’environnement.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
    </handlers>
    <httpPlatform processPath="c:\dev\javasites\bin\apache-tomcat-8.0.15\bin\startup.bat" 
                  arguments="" 
                  stdoutLogEnabled="true" 
                  stdoutLogFile="\\?c:\dev\javasites\log.txt">
      <environmentVariables>
        <environmentVariable name="JRE_HOME" value="%programfiles%\java\jdk1.8.0_25" />
        <environmentVariable name="CATALINA_OPTS" value="-Dport.http=%HTTP_PLATFORM_PORT% -Dsomeotherconfig=value"/>
        <environmentVariable name="CATALINA_HOME" value="c:\dev\javasites\bin\apache-tomcat-8.0.15" />
      </environmentVariables>
    </httpPlatform>
  </system.webServer>
</configuration>

Vous trouverez maintenant ci-dessous la configuration du gestionnaire telle qu’elle est proposée lors de la création d’un projet ASP.NET Core. Notez la présence de deux variables : DNX_PATH et DNX_ARGS. Celles-ci sont automatiquement alimentées par Visual Studio dès que vous choisissez de lancer votre application via IIS Express.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
    </handlers>
    <httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" startupTimeLimit="3600"/>
  </system.webServer>
</configuration>

Dans le cas d’une application ASP.NET Core, le but est de faire pointer l’attribut processPath vers une commande qui charge le bon environnement DNX, le bon hôte et son serveur HTTP.

Enfin, le gestionnaire HttpPlatformHandler est un gestionnaire natif. Cela signifie qu’il fonctionne sans code managé. Il est donc possible d’utiliser un application pool qui ne charge aucune version de la CLR lorsque vous déléguez la couche HTTP de vos applications à ce gestionnaire.

Kestrel

Ce serveur HTTP existe depuis le début d’ASP.NET Core, et était notamment utilisé par les développeurs sous Linux et MacOs, mais c’est depuis la bêta 8 qu’il se généralise réellement à toutes les plate-formes. Si vous utilisez le gestionnaire HttpPlatformHandler, vous allez faire pointer sa configuration vers un script qui se charge de restaurer le bon runtime puis démarre Kestrel.

Kestrel est donc un serveur web multi-plateformes, basé sur Libuv (la même librairie que node.js). Mais il ne s’agit que d’un serveur web, rien de plus. C’est-à-dire que Kestrel ne fait que lire et écrire des messages HTTP. Exit la gestion des logs, de l’authentification, du cache, etc. Ces concepts doivent être repris par d’autres couches ; par exemple par un serveur d’application tel que IIS.

C’est d’ailleurs l’approche désirée par Microsoft. Votre application ASP.NET Core est portée par l’hôte DNX et Kestrel et, selon si elle est déployée sous Windows ou Linux, c’est IIS ou Nginx qui fournissent alors les différents services de haut niveau.

A noter qu’il reste possible d’exécuter votre application sans serveur d’application, par exemple directement dans une application console. En fait cela se fait exactement de la même manière qu’en démarrant l’application au travers de IIS, sauf que c’est vous qui prenez en charge le démarrage du processus et non plus IIS.

Rendre une application compatible avec Kestrel est très simple. Utilisez le fichier project.json ci-dessous.

"dependencies": {
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final"
},

"commands": {
    "web": "Microsoft.AspNet.Server.Kestrel"
}

Puis, la classe Startup reste totalement indépendante à Kestrel.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    }
}

Pour démarrer l’application sans serveur d’application, c’est aussi très simple. Dans une invite de commande, naviguez vers le répertoire de votre application, saisissez les instructions suivantes. Vous pouvez également le faire au travers de Visual Studio en démarrant l’application via la commande web. Le résultat est le même.

dnu restore
dnx web

Pour démarrer l’application sous IIS Express, utilisez simplement la commande IIS Express sous Visual Studio. Dans ce monde de configuration, Kestrel est utilisé, mais c’est le gestionnaire HttpPlatformHandler qui est chargé de son instanciation.

Développer avec ASP.NET Core avec un serveur IIS local

Un cas de figure particulier que je souhaite évoquer : l’utilisation d’un serveur IIS local lors du cycle de développement. Il est parfois nécessaire de se brancher sur un serveur IIS local plutôt que IIS Express lorsque l’on souhaite que l’application pool qui exécute notre application utilise une identité spécifique et non pas l’identité courante.

Pour mettre en place ce genre de scénario, il faut suivre les étapes suivantes.

Tout d’abord, créer une application dans IIS. Son répertoire de base est le répertoire wwwroot de l’application ASP.NET Core. C’est-à-dire l’emplacement où IIS trouvera le fichier web.config permettant la configuration du gestionnaire HttpPlatformHandler.

L’application pool utilisée pour faire fonctionner cette application ne doit pas nécessairement charger une version de la CLR. La gestion de cette dernière sera assurée par DNX.

Il est ensuite nécessaire de mettre à jour le fichier web.config. Dans le cas de IIS Express, Visual Studio met à jour automatiquement les variables DNX_PATH et DNX_ARGS. Dans le scénario que je décris ici, c’est à nous de définir les bonnes valeurs pour ces variables.

Ainsi, vous pouvez utiliser le fichier de configuration suivant :

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
    </handlers>
    <httpPlatform processPath="../iis.cmd" arguments="" stdoutLogEnabled="false" startupTimeLimit="3600"/>
  </system.webServer>
</configuration>

Cette configuration fait référence à un fichier iis.cmd dont la définition est la suivante :

@echo off
SET DNX_FOLDER=dnx-clr-win-x86.1.0.0-rc1-final
SET "LOCAL_DNX=%~dp0runtimes\%DNX_FOLDER%\bin\dnx.exe"

@"%LOCAL_DNX%" --project "%~dp0project.json" web %*

Pour que ce script fonctionne, j’ai du faire quelques assertions (mais le tout pourrait probablement être automatisable) : un dossier runtimes doit être présent dans le dossier de l’application ASP.NET 5 et qui doit contenir la version du runtime spécifiée dans le script. Vous pouvez copier le runtime depuis votre répertoire utilisateur Windows (ex. C:\Users\Leo.dnx).

Il est également nécessaire que les paquets Nuget soient restaurés localement dans le dossier de l’application : par exemple, en utilisant un fichier global.json sous la forme suivante.

{
  "packages": "packages"
}

L’instruction suivante peut également être utilisée pour effectuer ce genre de restauration.

dnu restore --packages packages

Pour résumer, voici l’arborescence attendue pour votre projet.

src
    packages
        ...
    runtimes
        dnx-clr-win-x86.1.0.0-rc1-final
            ...
    wwwroot
        web.config
    global.json
    iis.cmd
    project.json
    Startup.cs

Et voilà. Vous pouvez à présent naviguer vers votre site hébergé sur le serveur IIS local et pointant vers le répertoire de développement.

Conclusion

J’espère que ce billet vous apporte les informations nécessaires à la compréhension dans les derniers changements de l’éco-système web de Microsoft. Kestrel et le gestionnaire HttpPlatformHandler sont sur le point de modifier en profondeur nos usages des serveurs d’applications lors du développement avec .NET. Cela entraîne un lot de nouveaux concepts et une perception des environnements de production différente de ce que nous connaissions. N’hésitez pas à suivre le blog de l’équipe ASP.NET et celui de l’équipe IIS pour rester au courant des dernières annonces.

Nombre de vue : 197

AJOUTER UN COMMENTAIRE