A la découverte de .NET Core !

L’écosystème .NET a connu de nombreux changement en 2015 notamment avec l’apparition des Universal Windows Platform app ou encore de la dernière version d’ASP.NET intitulé pour l’occasion ASP.NET Core 1. Les problématiques modernes de développement (cross-platform, cloud first, mobile first …) nous demandent à nous, développeurs, d’être toujours plus agile et performant dans nos développements d’aujourd’hui. De ce fait, nous demandons également à nos outils d’en faire de même, et de nous permettre de mieux nous adapter aux techniques de développement d’aujourd’hui.

La plateforme Microsoft ne déroge pas à la règle et c’est ainsi que .NET Core est né. Le framework .NET Core est initialement un simple fork du .NET Framework classique que l’on connait, mais en se focalisant sur les problématiques modernes de développement citées ci-dessus.

Principes de bases

Le .NET Core a été conçu en parallèle avec ASP.NET Core 1 afin de mieux servir le développement Web dans l’écosystème Microsoft et permet également de rassembler les principes suivants :

  • Pay-as-you-go signifie que le framework Core permet d’inclure dans vos déploiements uniquement ce dont il est nécessaire pour faire fonctionner votre application, et donc inutile d’installer des composants / librairies qui sont inutiles ;
  • Cross-platform intervient dans le domaine de la portabilité de l’application et permet ainsi de lancer une application Web sur un serveur Linux ou Mac OS ;
  • Cloud-optimized indique que le .NET Core est plus léger et permet un déploiement plus facile dans le cloud tout en garantissant uniquement les packages qui sont nécessaires à l’application et ainsi éviter de transférer des briques logicielles inutiles.

De plus, .Net Core est open-source et s’ouvre à la communauté pour le plus grand bonheur des contributeurs. Avec ceci, on se retrouve avec un Framework modulaire à souhait qui permet facilement de s’exporter vers d’autres plateformes et d’embarquer de lui-même les packages dont il a besoin (via NuGet). Nous allons voir un peu plus en détail ce qui compose .NET Core.

CoreCLR

Depuis les débuts du framework .NET,  la plateforme de Microsoft embarque année après année un moteur d’exécution très puissant appelé le Common Language Runtime. Ce dernier offre un environnement managé d’exécution des logiciels développés et permet une compilation à la volée pour ainsi transformer un code intermédiaire en code natif spécifique au système d’exploitation Windows.

Avec l’expansion de l’OpenSource dans le monde de l’informatique et l’impact du cloud dans nos développements d’aujourd’hui, Microsoft a du réécrire son célèbre moteur pour ainsi le rendre plus performant, cross-platform et plus léger. En effet, faisant partie intégrant de l’éco-système de .NET Core, CoreCRL se doit de fonctionner sur Windows, Linux et Mac. Une phrase résume assez bien la philosophie derrière CoreCLR :

Le but du CLR est de rendre la programmation plus facile

L’un des composants les plus connue de CoreCLR est le Garbage Collector, qui permet aux développeurs de travailler dans un environnement managé et donc d’éviter de se soucier des problématiques de libération de mémoire ou autre. Ce dernier a également été réécrit pour intégrer les nouvelles contraintes de .NET Core.

Deux éléments composent le GC aujourd’hui : l’allocateur et le collecteur. Chacun dans leurs rôles respectifs permet de gérer la mémoire soit en allouant sur demande de la mémoire pour les programmes, soit en collectant les objets en fin de vie ou inutilisés. Cependant, les principes de base du GC sont restés les mêmes :

  • Le GC doit s’exécuter assez souvent pour éviter que la pile se remplisse d’objet inutilisé ;
  • Le GC ne doit pas s’exécuter trop de fois non plus pour éviter d’utiliser trop de temps CPU ;
  • Le GC doit être éphémère et ne doit pas conserver de la mémoire ou du temps de CPU quand il ne s’exécute pas ;
  • Chaque collecte par le GC doit être rapide et efficace ;
  • Le code managé des développeurs ne doit pas connaître le GC.

Ecrit à la fois en C# et en C++, le CoreCLR contient approximativement 2,6 millions de ligne de code, et le GC à lui seul rassemble 55k lignes tout en utilisant un nouveau compilateur multiplateforme qui est CMake. De ce fait, Microsoft  réaffirme sa volonté de s’ouvrir à l’OpenSource.

CoreFX

Anciennement connu sous le nom de BCL (Base Class Library), CoreFX est le 2ème composant essentiel de .NET Core pour ainsi faire fonctionner les applications dans le nouvel écosystème de Microsoft. Composé de plusieurs librairies connu telles que System.Collections ou encore System.XML, ces briques logicielles possèdent maintenant le moins de dépendance entre elles, permettant ainsi de mieux moduler les importations faites dans les applications. Tout comme CoreCLR, CoreFX est distribué via des paquets Nuget et chaque librairie à son propre package.

L’exemple le plus probant que nous pouvons citer pour montrer toute l’ouverture de .Net Core est que la communauté Mono peut maintenant bénéficier de la librairie CoreFX et permet ainsi d’éviter de dupliquer des librairies communes. De plus, .NET ne se veut pas forcément plus « petit » que le framework .NET complet, mais puisque maintenant il suffit d’importer uniquement ce qu’on a besoin, les applications d’aujourd’hui auront un impact au niveau du déploiement moins significatif qu’avant. CoreFX participe également à sa manière à la révolution du Cloud.

Au niveau du code, CoreFX est écrit entièrement en C# et représente 25% du code du CoreCLR, soit à peu près 500k lignes de code.  L’avantage ici est que l’on détient alors une librairie consistante et managé quelle que soit la plateforme utilisé. Avec ceci, la librairie CoreFX inclut quelques nouveautés telles que :

  • Les FormattableString proposant de nouvelles méthodes pour mieux formaliser les chaînes de caractères selon des conventions de culture invariantes ;
  • Les ImmutableArray permettent de mieux gérer les collections fixes pour ainsi améliorer les performances et éviter tout problème au niveau de l’intégrité de la collection (notamment si ce sont des collections qui sont exposé via des API). Le pattern Builder est lui ici mis en pratique pour la côté amélioration des performances ;
  • Les Sockets et HttpClient sont maintenant disponibles via CoreFX ;
  • Inspiré du C++, on retrouve des classes telles que Vector2 ou Vector3 pour faciliter les calculs vectoriels. Ces dernières sont notamment utilisées dans l’API Composition disponible dans les Universal Windows Platform app afin de mieux gérer les animations ;
  • Certaines méthodes de la librairie Reflection sont maintenant devenus des méthodes d’extensions (comme GetMembers()).

Lors de la compilation avec CoreCLR, le résultat génère plusieurs éléments bien distincts. On retrouve l’exécutable d’un côté, les DLLs de CoreFX d’un autre côté et les références à des librairies externes à part également. En revanche, lors de la compilation en mode Release (avec .NET Native), le résultat génère une seule DLL avec tout le code managé et toutes les dépendances et librairies dont l’application a besoin pour fonctionner.

Les particularités de tous ces changements se retrouvent également dans la nouvelle version de NuGet. Dans les précédentes versions de .NET, les dépendances relatifs à NuGet était intégré au .csproj du projet, ce qui pouvait rendre difficile la maintenance via un contrôleur de code source. Les dépendances ont maintenant été séparé dans un projet à part intitulé project.json, permettant de mieux gérer les packages importés dans le projet. Chaque package peut potentiellement importer d’autres dépendances, qui nous sont inconnus, mais qui sont indispensables au bon fonctionnement de la librairie. NuGet va toutefois nous montrer uniquement les dépendances que nous avons importées, et non les autres, permettant ainsi de mieux se retrouver dans l’arborescence des dépendances. Il est quand même possible de voir toute la liste de dépendances importées dans le projet via le fichier project.lock.json. Via Nuget, la diffusion des librairies et du Framework s’en retrouve ainsi facilité, tout comme la diffusion des nouvelles fonctionnalités et des bugs fixes.

Roselyn

Grâce au CoreCLR et au CoreFX, nous avons ainsi de quoi faire fonctionner du code au runtime avec des librairies modulable à souhait, tout ceci optimisé pour le cross-platform et le cloud. Cependant, il est clair qu’un développeur souhaitant développer dans l’éco-système de Microsoft à partir de Linux ne pourra pas le faire puisqu’il ne possède pas de compilateur.

A ce sujet, Microsoft a publié sur GitHub il y a plusieurs mois son compilateur : Roselyn.  Avant le développement de l’OpenSource, les compilateurs étaient des boîtes noires et très peu de personnes ne pouvaient accéder au fonctionnement interne. Aujourd’hui, le monde a bien changé, et les compilateurs s’ouvrent et deviennent des APIs pouvant être utilisable dans d’autres contextes que des IDE. Les compilateurs deviennent des plateformes, permettant ainsi à la créativité de chacun d’opérer pour améliorer l’efficacité de ces outils.

Roselyn ne déroge pas à la règle, et a subit un profond remaniement afin de rendre le compilateur tel une plateforme utilisable de l’extérieur. Le pipeline d’exécution de Roselyn est le suivant :

Processus d'exécution de Roselyn

Processus d’exécution de Roselyn

Chaque phase est maintenant séparée en différents composants. La première phase est un simple parsing du code source pour mieux analyser la syntaxe suivant une certaine grammaire du langage (C#, VB …). On retrouve ensuite la phase de déclaration, permettant d’associer les métadonnées et les déclarations du code source pour former des symboles nommés. Ensuite, la phase d’association, ou de « bind », permettant d’associer les identifiants du code avec les symboles. Enfin, la dernière phase permet de reprendre toutes ces informations et de produire un assembly.

Chaque phase est alors exposée via un modèle objet permettant d’y accéder depuis l’extérieur. La phase de parsing est exposée via un arbre de syntaxe, la phase de déclaration via une table des symboles hiérarchique, la phase de « binding » via un modèle exposant le résultat de l’analyse et la dernière phase est représenté par une API qui produit le code intermédiaire.

Surcouche d'API afin d'accéder de l'extérieur au compilateur

Surcouche d’API afin d’accéder de l’extérieur au compilateur

Pour prouver la bonne faisabilité de ce mécanisme, Microsoft a intégré ces API dans Visual Studio 2015 via des menus comme Go to Definition, Object Browser ou encore Find all references. Devenu OpenSource, cross-platform et ouvert via des APIS, Roselyn est devenu un excellent outil de compilation qui permet maintenant bien plus d’usage qu’auparavant.

RyuJIT

RyuJIT est la nouvelle génération de compilateur développé par Microsoft et arrive avec la nouvelle boîte à outils proposé par .NET Core. Spécialement conçu pour les systèmes 64 bits, il sera à l’avenir la base pour tous les compilateurs de Microsoft : x86, ARM, MDIL …

Les principales caractéristiques de RyuJIT sont :

  • Amélioration des performances de compilations (jusqu’à 30% plus rapide au démarrage des applications) ;
  • Diminution de l’empreinte mémoire ;
  • Homogénéité du code entre plateforme 32 bits et 64 bits ;
  • Fin à la fragmentation du code des compilateurs.

Grâce au travail de fond réalisé par Microsoft, RyuJIT est supporté sur Linux et OS X. Intégré maintenant dans le .NET Core, RyuJIT est utilisé dans les nouveaux projets ASP.NET 5 pour assurer la portabilité de ces projets sur les autres plateformes.

.NET Native

Depuis les débuts de .Net, les applications conçues sur la plateforme de Microsoft subissaient d’abord une pré-compilation en code intermédiaire puis une 2ème compilation en code natif. Avec l’arrivée de .NET Native, il n’est plus nécessaire de passer par la pré-compilation pour faire fonctionner du code C# ou VB. Les applications sont ainsi plus rapides avec un faible coût de démarrage et une utilisation optimisée de la mémoire.

.NET Native est étroitement lié à .NET Core dans le sens où .NET Native est un ensemble d’outils, intégré à .NET Core, permettant de compiler des applications Universelles via une compilation statique AOT (ahead-of-time) avant son exécution, à l’inverse de CoreCLR qui compile à la volée. On retrouve alors 2 compilations bien distinctes en fonction du type d’application, mais utilisant les mêmes librairies sous-jacentes :

  • Compilation à la volée avec CoreCLR pour les applications ASP.NET Core 1 ;
  • Compilation AOT statique avec .NET Native pour les applications Universelles Windows 10.
Schéma résumant bien la disposition de .NET Core dans la plateforme de Microsoft

Schéma résumant bien la disposition de .NET Core dans la plateforme de Microsoft

Installation

Sur Windows

L’installation de .NET Core sur Windows se fait très facilement via l’installeur MSI officiel disponible sur le site https://dotnet.github.io qui va ainsi installer tous les outils nécessaires et les inclure dans le PATH de la machine. Pour initialiser ensuite une simple application Hello World, il suffit de lancer la commande suivante :

dotnet new

Ensuite il suffit de 2 commandes supplémentaires pour faire fonctionner l’application :

dotnet restore
dotnet run

La première commande va restaurer les packages NuGet nécessaire au bon fonctionnement de l’application, c’est l’équivalent du dnu restore. L’utilitaire va inspecter le project.json du projet pour récupérer les packages. Ensuite, la deuxième commande va simplement lancer l’application.

Sur Ubuntu (14.04)

Nous avons d’abord besoin de configurer notre apt-get et d’ajouter un nouveau répertoire qui contient les packages dont nous avons besoin :

sudo sh -c 'echo "deb [arch=amd64] http://apt-mo.trafficmanager.net/repos/dotnet/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893
sudo apt-get update

La commande suivante va installer .NET Core et toutes ses dépendances :

sudo apt-get install dotnet-dev-1.0.0-preview2-003121

Il suffit ensuite de reprendre les mêmes commandes que sur Windows pour lancer l’application sur Ubuntu. Attention tout de même, ce processus est encore en développement et peut être amené à changer dans les releases à venir.

Sur Mac OS X

Comme sur Windows, il est très simple d’installer .NET Core sur Mac. Il suffit tout d’abord d’installer le package officiel au format PKG téléchargeable depuis le site officiel de .NET Core. Ensuite, comme pour Windows, il suffit de lancer les 3 commandes suivantes :

dotnet new
dotnet restore
dotnet run

Cas pratique – intégration dans Visual Studio

L’intégration de CoreCLR est peu visible dans le code que nous écrivons de tous les jours, les nombreux changements sont plutôt dans les couches basses du Framework et difficilement identifiable en surface. Cependant, nous pouvons tout de même manipuler précisément le CoreCLR via Visual Studio et les nouveaux projets ASP.NET Core 1. Dans cette partie nous allons montrer les avantages de Visual Studio lorsqu’on manipule CoreCLR.

Commencez tout d’abord par créer un nouveau projet ASP.NET Core 1 via l’IDE. Prenez le template Web Application pour avoir quelque chose de complet.

Modèle ASP.NET 5

Modèle ASP.NET 5

La première des choses que nous pouvons remarquer lorsque le projet est chargé c’est que Visual Studio propose plusieurs modes d’exécution.

Les différents modes d'exécutions

Les différents modes d’exécutions

Grâce à cela il est ainsi possible d’exécution son application Web soit sur le Framework Full ou le Framework .NET Core. Cette configuration provient en fait du project.json de votre solution, et plus particulièrement de la section frameworks.

Framework ciblé par le projet ASP.NET Core 1

Framework ciblé par le projet ASP.NET Core 1

De base les projets ASP.NET Core 1 cible les 2 frameworks, mais le .NET Core n’étant pas encore complet, il se peut que vous deviez éliminer le .NET Core de la liste de vos frameworks cible. Dans ce cas, Visual Studio ne vous proposera plus d’exécuter le projet sur CoreCLR, mais il prendra automatiquement le framework complet.

Dans le cas où votre projet cible toujours les 2 frameworks, Visual Studio va vous aider à savoir si les APIs sont disponibles dans les 2 frameworks. Par exemple, prenons la classe XmlNodeReader. Au jour d’aujourd’hui (Mars 2016), la classe n’est pas disponible avec le .Net Core. Visual Studio va nous le signaler avec une erreur de compilation.

Erreur de compilation de Visual Studio

Erreur de compilation de Visual Studio

Pour pallier à ce problème, et si vous devez absolument utiliser cette classe, vous êtes obligé de supprimer « netcoreapp1.0 » de votre project.json.

Faites tourner ! Share on Facebook
Facebook
Tweet about this on Twitter
Twitter
Share on LinkedIn
Linkedin

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *