En novembre 2023, Microsoft a publié une nouvelle version d'ASP.NET, un framework open source multiplateforme pour la construction d'applications web modernes avec prise en charge du cloud. Alors, quelles sont les améliorations par rapport aux versions précédentes ?
La sortie d'ASP.NET Core 8.0 s'inscrit dans une politique de Microsoft initiée avec la version .NET 5, qui consiste à publier une nouvelle version du framework généralement en novembre de chaque année. L'objectif est de rendre le langage plus compétitif en le maintenant constamment à jour avec les demandes du marché.
Cette nouvelle version apporte des améliorations de performances, une intégration avec les technologies émergentes, de nouvelles API et bibliothèques, ainsi que des améliorations dans la prise en charge des conteneurs et l'orchestration. Vous trouverez ci-dessous plus de détails sur certaines de ces innovations.
Nouveau modèle d'application web Blazor
Dans cette nouvelle version, un nouveau modèle de projet Blazor appelé Blazor Web App a été introduit, combinant les fonctionnalités de Blazor Server et Blazor WebAssembly. D'autres modèles ont été consolidés, simplifiant ainsi le choix. Désormais, le modèle Blazor Web App peut être utilisé pour différents scénarios Blazor.
Avec cette technologie, il est désormais possible de diffuser du contenu en temps réel pendant le processus de rendu de la page. Cette avancée améliore significativement l'expérience utilisateur, permettant d'afficher le contenu au fur et à mesure de sa disponibilité, même sur des pages impliquant des tâches longues comme des requêtes de base de données étendues.
Initialement, la page est rendue avec des espaces réservés, et lorsque les opérations asynchrones sont terminées, le contenu mis à jour est diffusé et intégré dans la page en temps réel. Cette approche permet non seulement d'accélérer le chargement des pages, mais aussi de les rendre plus réactives aux interactions utilisateur.
Désormais, vous pouvez créer des composants Razor, comme du HTML au format texte ou flux, sans dépendre des requêtes HTTP ou de l'environnement d'hébergement ASP.NET Core. Cela est utile lorsque vous avez besoin de générer des fragments HTML, par exemple pour créer des e-mails ou du contenu de site web statique.
Plusieurs améliorations pour de meilleures performances
La génération de code est cruciale pour les performances des applications en .NET, et le compilateur Just-in-Time (JIT) en est responsable. .NET 8 apporte des améliorations significatives au JIT, notamment l'utilisation de l'Optimisation Guidée par Profil Dynamique (PGO), ce qui représente une avancée notable dans la qualité et les performances du code généré.
Le PGO dynamique est une stratégie d'optimisation de code qui s'appuie sur les actions réelles d'un programme lors de son exécution, pour améliorer son efficacité. Il est appelé "dynamique" car il observe et collecte des données sur le comportement du programme en temps réel et utilise ces informations pour créer une version plus efficace du code.
Grâce aux améliorations apportées au JIT, le processus de mise à zéro des variables a été optimisé. Lorsqu'une quantité importante de mise à zéro est nécessaire, le JIT utilise désormais une routine de mémoire optimisée au lieu de générer beaucoup de code pour obtenir le même résultat. Cette amélioration a été apportée pour optimiser les performances, rendant le processus plus efficace.
Une autre nouvelle fonctionnalité de .NET 8 est la vectorisation, une technique qui tire parti de la puissance de traitement parallèle du matériel, tel que les processeurs centraux modernes (CPUs), pour exécuter des opérations efficacement. Cela est particulièrement utile dans les opérations mathématiques et la manipulation de données, permettant de traiter plusieurs informations simultanément, accélérant les performances.
Dans .NET 8, le collecteur de déchets (GB) du serveur dispose également d'une nouvelle fonctionnalité appelée Adaptation Dynamique Aux Tailles d'Application (DATAS), qui permet un ajustement automatique de la mémoire en fonction des performances de l'application. Cette fonction n'est pas activée par défaut, mais peut être facilement activée via des variables d'environnement ou des propriétés MSBuild, aidant à équilibrer les performances de l'application et l'utilisation de la mémoire. Cette évolution sera décrite plus en détail plus loin.
Conteneurs
La capacité à exécuter des conteneurs Microsoft .NET en tant que non-root est désormais la configuration par défaut, améliorant la sécurité de l'application. Le tag de conteneur par défaut a été changé en "latest", rendant les conteneurs plus faciles à utiliser en développement. Ces changements visent à faciliter l'utilisation sécurisée et efficace des conteneurs .NET.
.NET 8 introduit également une variable d'environnement pour l'identification de l'utilisateur (UID) de l'utilisateur non-root, simplifiant les tests sur Kubernetes. Le port par défaut a été changé de 80 à 8080, et une nouvelle variable d'environnement (ASPNETCORE_HTTP_PORTS) a été ajoutée pour simplifier les changements de port. De plus, les tags d'image de conteneur pour les préversions .NET 8 n'auront plus le suffixe "-preview", et les nouveaux tags "8.0" et "8.0-<OS>" seront permanents et maintenus tout au long de la vie de .NET 8. Ces changements visent à améliorer la facilité d'utilisation et la sécurité des conteneurs .NET.
Sérialisation
.NET 8 introduit également plusieurs améliorations et nouvelles fonctionnalités significatives dans le domaine de la sérialisation, visant à améliorer la flexibilité et les performances de la sérialisation et de la manipulation des données.
La nouvelle version étend la compatibilité pour inclure de nouveaux types numériques tels que Half, Int128 et UInt128, ainsi que des structures de données comme Memory<T> et ReadOnlyMemory<T>. La plate-forme a également amélioré le générateur de code source pour fournir une expérience plus proche de l'AOT natif par rapport aux méthodes précédentes, ajoutant la prise en charge des types avec des propriétés obligatoires et init-only. Il introduit également des convertisseurs plus avancés et des formats de code généré plus propres.
De plus, il existe désormais un support robuste pour la sérialisation des propriétés faisant partie des hiérarchies d'interface, en introduisant des politiques de dénomination qui facilitent la conversion vers des formats comme snake_case et kebab-case.
La désérialisation a été étendue pour inclure les champs ou propriétés en lecture seule, ce qui n'était pas possible auparavant, et elle offre une option pour désactiver le sérialiseur basé sur la réflexion, idéale pour les applications utilisant des fonctionnalités de taille et de trim automatiques. Des méthodes supplémentaires ont été intégrées dans l'API JsonNode pour des opérations telles que le clonage en profondeur et la comparaison JSON, et de nouvelles fonctionnalités permettent l'inclusion de membres non publics dans le contrat de sérialisation.
La version inclut également des méthodes d'extension pour la désérialisation de IAsyncEnumerable<T> en streaming, une méthode d'extension pour modifier les contrats de sérialisation, et de nouvelles surcharges pour la création de contenu JSON qui sont conformes aux directives de sécurité de taille et de génération de code source.
Collecteur de déchets
Comme mentionné brièvement, .NET 8 introduit une fonctionnalité pour modifier dynamiquement la limite de mémoire, idéale pour les environnements de services cloud avec des demandes changeantes. Pour maximiser l'efficacité des coûts, les services peuvent désormais adapter les ressources consommées en fonction des variations de demande. Lorsqu'il y a une diminution des besoins, les services ont la possibilité de réduire la consommation de ressources en ajustant la limite de mémoire à la baisse.
Dans les versions précédentes, le GC pouvait ne pas reconnaître la nouvelle configuration, entraînant une allocation de mémoire supérieure à la limite ajustée. La nouvelle API RefreshMemoryLimit() résout ce problème en synchronisant le GC avec la limite de mémoire mise à jour.
Cependant, il y a des contraintes à considérer :
- Sur les systèmes d'exploitation 32 bits, .NET ne peut pas définir une nouvelle limite de tas maximale si elle n'existe pas déjà.
- L'API peut indiquer une erreur de mise à jour, qui peut se produire si la réduction de mémoire est excessive et ne laisse pas de place pour un fonctionnement efficace du GC. Si cela se produit, il est conseillé d'effectuer une collecte de déchets agressive avec GC.Collect(GCCollectionMode.Aggressive) pour réduire la consommation de mémoire avant de tenter à nouveau l'opération.
- De plus, augmenter la limite de mémoire au-delà de la capacité initiale estimée par le collecteur de déchets lors de l'initialisation peut ne pas entraîner l'utilisation effective de mémoire supplémentaire, même si le processus de mise à jour réussit.
Prise en charge native de l'AOT
La prise en charge de l'AOT natif (Ahead of Time) a été introduite dans .NET 7, permettant la création d'une version entièrement autonome d'une application qui élimine le besoin d'un runtime, car tout est compilé dans un seul fichier. Dans .NET 8, cette fonctionnalité a été améliorée avec la prise en charge des architectures x64 et Arm64 sur MacOS.
Il y a également eu une réduction significative de la taille des applications AOT natifs sur Linux, avec une diminution allant jusqu'à 50%. Il est désormais possible de choisir la préférence d'optimisation entre la taille et la vitesse. Par défaut, le compilateur cherche un équilibre entre un code rapide et une taille d'application réduite, mais vous pouvez définir la propriété MSBuild <OptimizationPreference> pour optimiser spécifiquement l'un ou l'autre critère. Pour plus de détails, vous pouvez vous référer à la documentation sur l'optimisation du déploiement AOT.
Conclusion
Ce ne sont là que quelques-unes des améliorations apportées à .NET 8. L'amélioration continue du framework par Microsoft contribue à le rendre de plus en plus adopté par les entreprises et plus populaire auprès des développeurs.
Le graphique ci-dessous illustre la tendance croissante de l'utilisation du langage de programmation C#, le plus populaire pour le développement .NET.