Retour

Vendredi 6 avril 2018

Le point sur ASP.NET Core

By Julien C.

 

Depuis quelques années, Microsoft montre une volonté d’unification de ses différents frameworks, pour une intégration simplifiée et multiplateforme. Ainsi, le rachat du framework Xamarin, comme la release du framework ASP.NET Core, s’inscrivent dans cette démarche. Mais qu’est-ce que ASP.NET Core exactement, et quelles sont les différences avec les anciennes versions des frameworks ASP.NET ? Je me propose de répondre ici à ces questions, et de voir en quoi ASP.NET Core peut répondre aux différentes problématiques qui se sont posées à ses prédécesseurs. Nous verrons dans le même temps les améliorations apportées dans sa version 2.0, puisqu’elles s’inscrivent dans la continuité directe des bases posées par ASP.NET Core 1.0, mais aussi ses lacunes et les problèmes que l’on peut encore rencontrer en développant une application .NET Core.

  En quelques mots : Comme énoncé précédemment, ASP.NET Core, a été conçu pour le développement d’applications sous Windows, Mac ou Linux, de manière indépendante et transparente. La scalabilité ainsi que les performances ont été améliorées, l’intégration de micro-services simplifiée, et a été ajoutée la possibilité d’utiliser des conteneurs Docker. ASP.NET Core utilise le runtime .NET Core, qui peut se lancer de la même manière sous Windows, MacOS ou Linux. Tout en maintenant la ligne directrice posée par les frameworks .NET au fil des ans, Microsoft souhaite dans ce nouveau framework faciliter l’intégration de plus en plus présente de micro-services, indépendamment de leur technologie d’origine. Vous l’aurez compris, ASP.NET Core regroupe toutes les fonctionnalités des anciens frameworks .NET. Il contient les dernières versions de .NET MVC, Web API, Web Pages et SignalR, et permet de les utiliser indépendamment dans la même application. C’est en cela que ASP.NET Core est vu comme une plateforme de développement nouvelle génération, et comme le framework le plus abouti de Microsoft. Les différences fondamentales / structurelles

> Hosting

Les applications ASP.NET Core n’ont plus besoin d’IIS pour l’hébergement. Elles peuvent à présent être self-hosted, ou hébergées sur Nginx pour les distributions Linux. Cela vient de la volonté de pouvoir lancer une application .NET Core indépendamment sur toutes les plateformes.  

> Runtime

S’inscrivant dans la même démarche, Le runtime est depuis la version 2.0 dépendant de la distribution, et non plus de la version. Cette modification a été apportée en ciblant principalement Linux, mais est également vraie pour MacOS et Windows. Il n’y aura plus de runtime individuel pour Windows 10 et Windows 8, par exemple. Cela permet d’étendre les plateformes supportées pour le développement d’applications ASP.NET Core.

> Une stack web unique pour ASP.NET Core MVC et Web API

L’une des différences fondamentales pour nous autres développeurs, est d’avoir une stack web partagée par MVC et Web API. On peut voir ici que, contrairement à ASP.NET MVC 5, ASP.NET Core ne permet pas d’ajouter les références de Web API, car elles sont déjà inclues dans les références de base, et partagent la même stack que .NET Core MVC. En plus de permettre un gain de place en mémoire physique, cela permet d’améliorer les performances globales de l’application.

> Référencement de librairies et migration d’applications

L’une des corrections majeures de la version 2.0 de .NET Core réside dans le référencement de librairies externes. Pour citer une annonce de Microsoft portant sur .NET Core 2 / .NET Standard 2 : “You can now reference .NET Framework libraries from .NET Standard libraries using Visual Studio 2017 15.3. This feature helps you migrate .NET Framework code to .NET Standard or .NET Core over time (start with binaries and then move to source). It is also useful in the case that the source code is no longer accessible or is lost for a .NET Framework library, enabling it to be still be used in new scenarios. “We expect that this feature will be used most commonly from .NET Standard libraries. It also works for .NET Core apps and libraries. They can depend on .NET Framework libraries, too. En d’autres termes, les librairies visant .NET Core 2 peuvent référencer d’anciennes librairies portées sur le full framework .NET, sans que cela ne pose de problème. Cette correction de rétro-compatibilité, très attendue de la communauté de développeurs, permet à elle seule une migration -presque- directe d’une application .NET vers .NET Core 2. Voici un exemple simple, avec une librairie que j’affectionne particulièrement : TopShelf, qui permet la création de services Windows. Pour diverses raisons, Topshelf n’avait pas été migrée pour être supportée par .NET Core 1.0 (la librairie référençait de nombreuses API non supportées sur cette version).   Install-Package Topshelf La tentative d’installation se soldait par une erreur assez célèbre chez les développeurs de .NET Core de la première heure : La même commande, dans une application .NET Core 2.0, mène à un résultat bien plus satisfaisant : Ô joie, je peux maintenant utiliser l’une de mes librairies préférées dans mes projets personnels. Sauf que. On remarque rapidement que la librairie en question est marquée d’un warning dans l’arborescence de projet : Un test rapide (en utilisant le QuickStart présent dans la documentation de TopShelf) : Confirmera nos craintes : impossible, malgré les promesses de Microsoft, de faire fonctionner la librairie dans notre application. C’est là que le bât blesse : de nombreuses librairies sont encore inaccessibles, même dans la version 2.0. Cependant, de ce point de vue là les choses sont en bonne voie. Le fer de lance de .NET Core 2 est à la fois sa compatibilité et son caractère Plateform agnostic. Par conséquent, les efforts de l’équipe de Microsoft sont clairement dirigés en ce sens. Les différences dans l’architecture

> Configuration et packages

La configuration de l’application a subi de nombreux changements dans ASP.NET Core. Adieu le fichier web.config où s’ajoutaient au fil de la vie de l’application et de l’intégration d’API externes des dizaines et des dizaines de lignes, désormais la configuration « dure » de l’application et managée dans le fichier app.config. Il y a également une évolution concernant la gestion des packages client (qui ne font techniquement pas partie d’ASP.NET Core, par exemple les dépendances NPM ou Bower) et serveurs (typiquement, les NuGet Package), qui ont été séparés, respectivement dans les dossiers Dependencies et References. Les Dependencies sont référencées dans le fichier package.Json (à la manière d’un framework Javascript), tandis que les References sont gérées dans le fichier *.csproj. Encore une fois, cela permet un gain de mémoire pour les applications .NET Core. Dans les versions précédant .NET Core, on utilisait le NuGet Package Manager pour télécharger des packages externes. Ce dernier créait un dossier « Packages » dans la structure de la solution. Depuis .NET Core 2, les packages sont stockés puis référencés depuis le dossier Utilisateurs de Windows (feature appellée Runtime Store for .NET Core 2), ce qui permet d’éviter la redondance de packages, et donc de gagner du temps à l’étape du build, lors du développement de plusieurs applications.

> Le dossier wwwroot

Le dossier wwwroot (le nom peut éventuellement être modifié via la methode UseWebRoot) fait également son apparition dans l’architecture .NET Core. Il s’agit du répertoire root de votre application web, et il permettra de stocker toutes les ressources statiques (qu’elles soient en css, html, js, des images, des librairies…) de votre application. Les accès sont gérés nativement, et cela permet de garantir que les fichiers en dehors du dossier racine (comme le fichier config.json) ne soit jamais accessible. En outre, cette architecture facilite certains process tels que la minification ou le build automatisé via Grunt.

> Injections de dépendances

L’injection de dépendances a toujours été au cœur des problématiques liées au développement, puisqu’elle permet un couplage faible et une meilleure testabilité du code. L’équipe derrière .NET Core l’a bien compris, puisque le framework intègre une architecture complète liée à l’injection de dépendance (ID dans la suite du paragraphe) et à l’inversion de contrôleur (IoC), sous la forme d’un conteneur simple (l’interface IServiceProvider) qui gère l’injection de contrôleur par défaut, et les différents services qui lui seront accessibles. Contrairement aux versions précédentes des frameworks .NET, où l’utilisation de conteneurs externes (Autofac, Unity, StructureMap…) était requise, le fait d’avoir une gestion native des ID simplifie grandement la mise en place du projet en limitant les outils externes nécessaires au build. Les services disponibles dans le conteneur sont configurables dans la classe Startup :  

> Gestion des « User Secrets »

On notera également l’apparition du Secret Manager, un outil aidant à la gestion des données sensibles propres au développeur, et qui évite l’erreur de les commiter en même temps que les nouveaux développements. Microsoft nous met cependant en garde, « The Secret Manager tool does not encrypt the stored secrets and should not be treated as a trusted store. It is for development purposes only. »  La gestion de ces Secrets se fait directement via une option présente dans Visual Studio : au clique droit sur un projet Cette opération crée un fichier Secret.Json, qui correspond à une sauvegarde au format Json de toutes les chaines de connexion, les divers credentials… Ce fichier est sauvegardé localement et à l’écart de notre solution, ce qui permet d’éviter les fameuses erreurs de credential commit qui n’apportent que la honte au sein d’une équipe :   Les différences en pratique Les Pages Razor Une des nouveautés d’ASP.NET Core 2 est l’apparition des Pages Razor. Cette fonctionnalité doit être activée dans la class Startup via injection de dépendances : Ces nouvelles pages permettent la mise en place de vues indépendantes de contrôleurs, et rend donc le développement de scénarios orienté Page plus fluide tout en clarifiant l’architecture de votre solution : La directive @page permet de signifier que le fichier est une action MVC, et donc qu’il gère les demandes directement sans passer par un contrôleur. Il est bien sûr possible d’utiliser une page en lien avec un model : Nous verrons plus en détail dans un prochain article les différentes possibilités qu’offre cette nouvelle fonctionnalité.