Accueil .NET 10 - Nouveautés, Performances et Support Prolongé
Post
Annuler

.NET 10 - Nouveautés, Performances et Support Prolongé

En novembre 2025, Microsoft lancera .NET 10, probablement lors de .NET Conf (du 11 au 13 novembre). Cette version s’annonce riche en améliorations de performance et nouvelles fonctionnalités, tout en apportant des changements de support importants. À l’heure où j’écris cet article en fin septembre 2025, .NET 10 est en RC1 (depuis le 9 septembre), et la version finale sera une LTS (Long Term Support) prise en charge jusqu’en novembre 2028. Notons d’ailleurs un ajustement de stratégie : les versions STS (Standard Term Support, impaires comme .NET 9) bénéficient désormais de 24 mois de support au lieu de 18 auparavant. En clair, .NET 9 (sorti en 2024) aura sa fin de support repoussée à novembre 2026, soit le même jour que .NET 8 LTS.

.NET 10 étant une version majeure, il est illusoire de vouloir lister tous les changements dans un seul article. Nous allons donc nous concentrer sur les faits marquants. Préparez-vous à découvrir des gains de performance notables, des nouveautés du côté du framework et du langage C#14, ainsi que quelques conseils sur la migration.

Des performances encore améliorées

Chaque nouvelle version de .NET apporte son lot d’optimisations, et .NET 10 ne fait pas exception. L’ingénieur Stephen Toub a publié son traditionnel pavé de plus de 200 pages détaillant “des centaines de petites améliorations qui, mises bout à bout, rendent .NET 10 plus rapide”. Inutile de chercher une révolution unique : les gains viennent d’une multitude de micro-optimisations dans le JIT, le GC, les collections, etc., qui grattent des nanosecondes par-ci, quelques octets par-là, sur des opérations exécutées des milliards de fois. Par exemple, le runtime est désormais plus intelligent pour allouer certains objets sur le stack plutôt que dans le heap (grâce à l’escape analysis), évitant des allocations mémoire. Les boucles foreach sur des collections sont un poil plus efficaces, tout comme de nombreuses méthodes LINQ courantes qui ont été retravaillées.

En somme, .NET 10 est encore plus performant. Vos applications web, services et outils gagneront en rapidité sans changer une ligne de code, grâce aux améliorations du JIT, des algorithmes de tri, du threading et bien d’autres. De quoi faire plaisir aux développeurs en quête de performance… et aux utilisateurs finaux qui apprécieront la réactivité.

Nouvelles fonctionnalités côté framework et runtime

JSON Patch intégré à System.Text.Json

Enfin une bonne nouvelle pour les API REST : .NET 10 introduit une implémentation native de JSON Patch (RFC 6902) basée sur System.Text.Json. Jusqu’à présent, appliquer un patch JSON dans ASP.NET Core nécessitait la bibliothèque externe Newtonsoft.Json. Désormais, plus besoin de cet extra, on peut manipuler des JsonPatchDocument directement via System.Text.Json, avec de bien meilleures performances et une empreinte mémoire réduite. Concrètement, un package Microsoft.AspNetCore.JsonPatch.SystemTextJson fait son apparition pour activer cette fonctionnalité dans vos contrôleurs Web API.

💡 Note : cette nouvelle implémentation ne gère pas les types dynamic et n’est pas totalement compatible à 100% avec l’ancienne (quelques cas limites diffèrent). Mais pour l’écrasante majorité des usages, on peut enfin se passer de Newtonsoft et appliquer proprement des opérations de patch (add, remove, replace, etc.) sur nos modèles JSON.

Observabilité renforcée : métriques ASP.NET Core

Les équipes .NET ont beaucoup travaillé sur l’observabilité. .NET 10 enrichit ASP.NET Core de nouvelles métriques intégrées pour mieux monitorer vos applications. Par exemple, le framework expose désormais des compteurs (counters, histograms…) pour suivre les événements d’authentification et d’autorisation : nombre de nouvelles créations d’utilisateurs, changements de mot de passe, tentatives de connexion, etc. Des métriques spécifiques à ASP.NET Core Identity ont été ajoutées pour mesurer la durée de certaines opérations (exemple : aspnetcore.identity.user.create.duration pour la création d’un utilisateur).

De même, le gestionnaire de mémoire interne d’ASP.NET (pools de mémoire) expose maintenant des compteurs de «memory eviction», utiles pour voir si votre application évacue souvent des données du cache en mémoire. Même Blazor a droit à des métriques de cycle de vie de composant et du traçage plus poussé, ce qui facilitera le diagnostic de vos applications WebAssembly côté client.

Toutes ces métriques sont accessibles via le système de métriques .NET (basé sur EventCounters/OpenTelemetry Metrics). En clair, vous pouvez brancher vos tableaux de bord de monitoring (Prometheus, Grafana, Application Insights…) et obtenir une observabilité fine sans écrire de code maison. Un vrai plus pour détecter les goulots d’étranglement et surveiller la santé de vos applications en production.

Sécurité et identité : support des Passkeys

La révolution passwordless arrive dans .NET 10 ! ASP.NET Core Identity prend désormais en charge les Passkeys (clés d’authentification FIDO2/WebAuthn). Concrètement, le template d’application Blazor (avec identité individuelle) a évolué : l’espace « Passkeys » permet aux utilisateurs d’enregistrer une clé biométrique ou un appareil de sécurité pour se connecter.

Les passkeys fournissent une méthode d’authentification sans mot de passe, utilisant des dispositifs biométriques ou des clés sécurisées liées à l’appareil de l’utilisateur. Avec .NET 10, on peut donc offrir aux utilisateurs la possibilité de se connecter avec Windows Hello, Touch ID, clés USB de sécurité, etc., plutôt qu’avec le traditionnel couple login/mot de passe. C’est à la fois plus sécurisé (immunisé contre le phishing) et plus pratique une fois configuré.

Petite dose de réalisme toutefois : dans l’état actuel (Preview 6), le gabarit impose encore de créer un mot de passe lors de l’inscription initiale, le passkey venant en option ensuite. Cela a fait tiquer certains (après tout, le but des passkeys est d’éliminer totalement les mots de passe…). Gageons que de futures itérations permettront une inscription 100% sans mot de passe. Quoi qu’il en soit, intégrer WebAuthn nativement dans le framework est un grand pas en avant. Si la sécurité de vos applications web vous tient à cœur, vous pourrez tirer parti de cette fonctionnalité pour proposer le login le plus sûr à vos utilisateurs.

Mode script en C#

Avec .NET 10, Microsoft continue de faciliter la vie des développeurs en matière de déploiement et de prototypage. Le Mode script C# (dotnet run <fichier>.cs) est l’une des nouveautés les plus cool pour les développeurs : .NET 10 permet d’exécuter directement un fichier .cs sans projet ni solution. En tapant simplement dotnet run monScript.cs, le SDK compile et lance le code C# immédiatement. Idéal pour tester un bout de code, écrire un petit utilitaire jetable, ou apprendre C# sans passer par la case .csproj. Plus besoin de créer un projet complet pour un programme de 5 lignes ! Cette expérience « script » rapproche C# de langages comme Python ou JavaScript pour les scenarios rapides. (Ne jetez pas encore Visual Studio, pour des applications sérieuses, le projet reste pertinent, mais pour un script d’administrateur, c’est la vie.)

.NET 10 améliore la productivité sur tout le cycle de vie : du prototype au déploiement final.

Évolutions du langage C# 14

Qui dit nouvelle version .NET dit souvent nouvelle version du langage C#. .NET 10 s’accompagne de C# 14, qui apporte quelques raffinements très appréciables pour les développeurs, sans bouleverser la syntaxe existante.

Extension Members : la fonctionnalité “extension everything

C# 14 réalise un fantasme de longue date : permettre des members d’extension, pas juste des méthodes. Depuis C# 3.0 (en 2007), on peut écrire des méthodes d’extension (extension methods) pour ajouter des méthodes “virtuelles” à des types existants. Mais on ne pouvait pas créer de propriétés d’extension, ni étendre les méthodes statiques. Plusieurs tentatives avaient échoué dans le passé, surnommées “extension everything”. Cette fois c’est la bonne : les extension members débarquent en C# 14.

Concrètement, une nouvelle syntaxe permet de déclarer dans une classe statique un bloc extension ciblant un type (par exemple IEnumerable<T>) et d’y définir :

  • des propriétés d’extension (comme un IsEmpty accessible sur n’importe quel IEnumerable<T>),
  • des méthodes d’extension statiques (s’apparentant à des méthodes de classe du type étendu),
  • même des opérateurs d’extension (surcharge de operator+ par exemple) qui agissent comme si le type les proposait nativement.

Cette syntaxe est un peu verbeuse au premier abord, mais elle organise mieux le code.

Par exemple, on peut maintenant écrire :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class Enumerable 
{
    extension<T>(IEnumerable<T> source)
    {
        public bool IsEmpty => !source.Any();               // propriété d’extension
        public IEnumerable<T> Where(Func<T,bool> p) {  }   // méthode d’extension (instance)
    }

    extension<T>(IEnumerable<T>)
    {
        public static IEnumerable<T> Combine(IEnumerable<T> first, IEnumerable<T> second) { ... }  // méthode statique d’extension
        public static IEnumerable<T> operator+ (IEnumerable<T> left, IEnumerable<T> right) => left.Concat(right); // opérateur d’extension
    }
}

Dès lors, je peux appeler maListe.IsEmpty comme s’il s’agissait d’une propriété native du type List, ou encore IEnumerable<int>.Combine(seq1, seq2) comme une méthode statique de IEnumerable Ça rend le code plus lisible et discoverable (surtout dans IntelliSense) qu’une méthode d’extension classique perdue dans une classe utilitaire. Bref, une fonctionnalité favorite de beaucoup (dont moi-même 😊), qui va permettre de mieux organiser nos extensions.

(Et pour les puristes : pas de panique, vos méthodes d’extension actuelles continuent de fonctionner comme avant, cette nouvelle syntaxe est optionnelle et rétrocompatible.)

Mot-clé field : propriétés auto-gérées

Autre petit sucre syntaxique bienvenu : le mot-clé field, qui simplifie la gestion des champs privés dans les propriétés. Si vous avez déjà implémenté manuellement le backing field d’une propriété pour, par exemple, contrôler la valeur lors du set (value ?? throw…), vous savez que c’est un peu verbeux. C# 14 permet maintenant d’écrire directement la logique dans l’accesseur set, en utilisant field pour représenter le champ sous-jacent.

Exemple : au lieu de :

1
2
3
4
5
6
private string _msg;
public string Message 
{
    get => _msg;
    set => _msg = value ?? throw new ArgumentNullException(nameof(value));
}

On peut écrire simplement :

1
2
3
4
5
public string Message 
{
    get;
    set => field = value ?? throw new ArgumentNullException(nameof(value));
}

Le compilateur se charge de générer le champ privé caché. Le code est plus concis et clair. Bien sûr, field n’est valable que dans le contexte d’un accesseur de propriété, il représente le stockage interne. Attention si vous avez déjà une variable nommée field dans votre classe, cela peut ambiguïser, il est conseillé de la renommer ou d’utiliser @field pour lever l’ambiguïté.

Numeric String Comparer : le tri “humain” débarque

Un petit irritant qui nous donnait la vie dure : le tri de chaînes “avec des nombres” rend souvent des résultats surprenants. Par exemple, quand on trie des versions ou des étiquettes comme ["v1", "v2", "v10"], un tri lexicographique donnera quelque chose comme ["v1", "v10", "v2"], ce qui est contre-intuitif. 😅

Avec .NET 10, le numeric string comparer corrige cela. Il permet de comparer les chaînes en traitant les morceaux numériques à l’intérieur comme des nombres, ce qui donne un tri “logique” :

1
2
3
4
5
6
7
8
9
var list = ["Windows 10", "Windows 7"];

// tri par défaut

list.Sort(StringComparer.Orginal);
Console.WriteLine(string.Join(", "), list)); // "Windows 10", "Windows 7"

list.Sort(StringComparer.NumericOrdering);
Console.WriteLine(string.Join(", "), list)); // "Windows 7", "Windows 10"

Pourquoi c’est utile :

  • Pour trier des versions ou des tags dans les interfaces utilisateurs, logs, ou listes de fichiers, où le résultat “humain” est préférable.
  • Pour le frontend ou les API qui renvoient des listes de fichiers ou de révisions, afin d’éviter de devoir post-traiter ou écrire une logique “maison”.
  • Pour les développeurs de NuGet ou outils CLI qui manipulent des noms de versions, identifiants, etc.

nameof plus puissant et autres bricoles

Le mot-clé nameof(...) évolue aussi légèrement : il supporte à présent les types génériques non construits (unbound generic types). En clair, vous pouvez obtenir le nom d’un type générique sans spécifier ses paramètres. Par exemple, nameof(Dictionary<T>) renverra “Dictionary” (ou une forme qui indique les paramètres génériques). Auparavant, ce n’était pas possible directement, ce qui obligeait à des contournements. Ce changement, bien que mineur, facilite la réflexion ou la génération de code source en évitant des exceptions ou manipulations de chaînes peu élégantes.

Parmi les autres nouveautés de C# 14, plus ponctuelles, citons : les opérateurs d’affectation composés personnalisés (on peut surcharger operator += par exemple, si le type supporte déjà +), les constructeurs partiels (utile pour les générateurs de code source), la possibilité d’ajouter des modificateurs ref, out ou params aux paramètres des lambdas, ou encore l’affectation null-conditionnelle (x?.Prop = value qui évite de devoir faire un if null avant d’assigner). Ces raffinements visent à rendre le langage plus cohérent et expressif, sans bouleverser vos habitudes.

Améliorations ASP.NET Core et écosystème

Minimal APIs : support de ProblemDetails et autres

Le modèle des Minimal API (introduit en .NET 6) continue de combler ses manques. En .NET 10, la gestion des erreurs de validation de modèle s’améliore : les minimal APIs intègrent désormais nativement le support de IProblemDetailsService pour formater les réponses d’erreurs. En d’autres termes, si vous avez des Endpoints en minimal API qui valident l’entrée et retournent une 400 en cas d’erreur, vous pourrez profiter d’une réponse JSON standardisée ProblemDetails sans effort supplémentaire. Fini les tours de magie pour aligner le format d’erreur sur celui du reste de votre application : le framework fournit une sortie cohérente, et vous pouvez même la personnaliser en enregistrant votre implémentation de ProblemDetailsService (par exemple, pour ajouter un code erreur personnalisé, un lien de documentation, etc.).

Au niveau des APIs, ASP.NET Core 14 supporte aussi pleinement les Server-Sent Events (SSE) en sortie des contrôleurs ou minimal APIs, via une méthode utilitaire TypedResults.ServerSentEvents(...). Cela facilite l’envoi de flux temps-réel du serveur vers le client sans WebSockets (utile pour du monitoring, des notifications live, etc.). C’était faisable à la main avant, mais là encore le framework le prend en charge nativement.

Ouverture et standards : OpenAPI 3.1 et gRPC

Le support d’OpenAPI 3.1 est désormais intégré dans .NET 10. Si vous générez la documentation Swagger de vos APIs, elle sera produite par défaut au format OpenAPI 3.1 (au lieu de 3.0 précédemment). Cette version 3.1 apporte notamment une meilleure prise en charge de JSON Schema 2020-12 (ceux qui ont sacré avec les schémas de nullabilité en OpenAPI 3.0 apprécieront : plus besoin du champ nullable: true, on utilise directement un type null dans le schéma). Concrètement, vos int et long nullable apparaîtront correctement comme type: ["integer","null"] dans le JSON de la spécification. Quelques changements breaking sont à noter dans la librairie OpenAPI.NET interne (passage en v2.0 de Microsoft.OpenApi), surtout si vous avez écrit des document filters ou operation filters custom : les types ont un peu changé (les schémas utilisent une interface IOpenApiSchema au lieu d’une classe concrète, etc.). En résumé, .NET suit l’évolution du standard OpenApi, pour que vos APIs restent au goût du jour.

Pendant qu’on parle de services web : du côté de gRPC, notons une amélioration sympathique : la gestion du streaming côté client (Client Streaming) devient plus ergonomique. .NET 10 apporte la prise en charge des message handlers HTTP dans les appels gRPC client, permettant des scénarios de retry ou de logging plus intégrés. (D’accord, c’est un peu pointu, mais si vous faites du gRPC, jetez un œil aux release notes pour découvrir ces ajustements.)

EF Core 10 : filtres globaux nommés et Left Join

Entity Framework Core 10 accompagne la sortie de .NET 10, et apporte lui aussi son lot de nouveautés. Le plus notable est sans doute l’arrivée des filtres de requête nommés (named query filters). EF Core propose depuis longtemps les filtres globaux (HasQueryFilter) pour, par exemple, implémenter le soft delete (exclure les entités dont IsDeleted = true) ou la multi-tenance (filtrer par TenantId). Cependant, jusqu’à présent on ne pouvait définir qu’un seul filtre global par entité, pas très pratique si l’on voulait combiner, puis en désactiver un sélectivement. EF 14 lève cette limitation : on peut maintenant attacher plusieurs filtres globaux sur un même modèle en leur donnant un nom unique.

Exemple :

1
2
3
modelBuilder.Entity<Blog>()
    .HasQueryFilter("SoftDeletionFilter", b => !b.IsDeleted)
    .HasQueryFilter("TenantFilter", b => b.TenantId == tenantId);

Puis, dans une requête LINQ, décider d’ignorer l’un des deux filtres :

1
2
3
4
5
// Récupérer tous les blogs en incluant ceux supprimés, 
// mais en gardant le filtre de Tenant
var allBlogs = context.Blogs
    .IgnoreQueryFilters("SoftDeletionFilter")
    .ToList();

Cette granularité était très attendue pour les applications complexes : on peut enfin combiner proprement des filtres globaux multiples (et éviter les contorsions du style Enable/Disable Filter sur tout le contexte).

Parmi les autres améliorations d’EF Core 14, on notera le support direct des jointures Left Join et Right Join en LINQ. Auparavant, écrire une requête LINQ équivalente à un LEFT JOIN SQL demandait une syntaxe peu intuitive avec GroupJoin + DefaultIfEmpty.

Désormais, on dispose d’une méthode d’extension .LeftJoin(...) (et .RightJoin(...)), rendant le code plus lisible.

Par exemple :

1
2
3
4
5
6
7
var query = context.Students
    .LeftJoin(
       context.Departments,
       student => student.DepartmentID,
       dept => dept.ID,
       (student, dept) => new { student.Name, Department = dept.Name ?? "[NONE]" }
    );

EF Core sait traduire ça en SQL (LEFT JOIN ou RIGHT JOIN). Cela ne change rien en termes de performance par rapport à avant, mais niveau lisibilité du code, c’est le jour et la nuit.

Enfin, EF 14 ajoute plein de petits plus : la recherche Full-Text sur Azure Cosmos DB, des traductions SQL supplémentaires (exemple, la méthode DateOnly.ToDateTime() désormais convertie nativement en SQL), des améliorations de performance sur les split queries (pour éviter des incohérences de tri dans les requêtes fractionnées), etc. De quoi rendre vos accès aux données plus flexibles et efficaces.

En route vers .NET 10 : faut-il migrer ?

La grande question pour les équipes : devez-vous passer à .NET 10 rapidement ? La réponse dépend de votre situation, mais voici quelques éléments de réflexion :

  • .NET 10 est une version LTS (support long), ce qui en fait un candidat solide pour vos applications en production. Elle sera supportée 3 ans (jusqu’à la fin de 2028), ce qui donne une vision claire à long terme. Si vous êtes encore sur .NET 8 LTS, rien ne presse (le support de .NET 8 court jusqu’en nov. 2026, mais .NET 10 représente la prochaine cible LTS “naturelle”).
  • Si vous êtes sur .NET 9 (STS), notez que le nouvel alignement du support fait que .NET 9 expirera en même temps que .NET 8 en 2026. Autrement dit, .NET 9 ne prolonge pas votre horizon par rapport à .NET 8. Dans ce cas, migrer vers .NET 10 (LTS) dès que possible vous remet sur un cycle plus confortable.
  • Les gains de performance et les nouvelles fonctionnalités peuvent justifier la migration, surtout si vous avez besoin de l’une des nouveautés (par exemple, le JSON Patch natif ou les passkeys pour vos utilisateurs). .NET 10 apporte aussi de nombreuses corrections de bugs et améliorations de stabilité accumulées depuis .NET 8 et .NET 9.
  • Breaking changes : évidemment, qui dit nouvelle version dit potentiels changements incompatibles. Microsoft a publié la liste des breaking changes de .NET. Au moment de la RC1, cette liste n’était pas totalement finalisée, mais on sait déjà qu’il y aura quelques ajustements de comportements (par exxemple, le nameof sur types génériques mentionné plus haut, ou des API retirées après obsolescence). Avant de migrer, examinez attentivement ces notes de compatibilité pour évaluer l’impact sur votre code. La plupart du temps, l’upgrade se passera sans encombre pour du code standard, mais mieux vaut prévenir que guérir !

En pratique, .NET 10 s’annonce comme une version mature et aboutie, avec un bel équilibre entre performance, productivité et modernisation du stack. Si vos tests de validation passent et que vos dépendances (NuGet, frameworks) supportent .NET 10, il n’y a pas de raison d’attendre trop longtemps. Microsoft elle-même encourage la mise à niveau : “Si vous prévoyez de passer de .NET 9 à 10 bientôt, continuez dans cette voie, .NET 10 apporte plein de nouvelles capacités et de meilleures performances”.

Pour finir : outillage et écosystème

Un dernier mot pour les développeurs curieux : en parallèle de .NET 10, Microsoft commence à dévoiler la prochaine version de Visual Studio. Eh oui, Visual Studio 2026 (Insiders) est déjà disponible en aperçu. Au menu : améliorations de l’éditeur, support de C# 14 bien sûr, et d’une intégration toujours plus poussée de GitHub Copilot et de l’IA. Vous pouvez installer Visual Studio 2026 Insiders en parallèle de votre installation existante sans risque, la grande majorité des extensions de Visual Studio 2022 sont compatibles, et dès cette version la couverture de code est incluse par défaut dans toutes les éditions, inutile désormais d’avoir la version Entreprise pour en profiter.

Enfin, l’écosystème .NET suit le mouvement : attendez-vous à voir arriver Entity Framework 14, ASP.NET Core 14, Blazor, MAUI 14, etc., alignés sur cette nouvelle mouture. Les outils de build, CI/CD, containers Docker et autres seront mis à jour également. La documentation Microsoft Learn est enrichie progressivement (il existe déjà des pages “What’s new” pour .NET 10, EF 14, C# 14… très utiles pour approfondir chaque nouveauté).

En résumé, .NET 10 marque une étape importante en 2025 pour les développeurs .NET. Support étendu, optimisation de tous les recoins du runtime, nouvelles fonctionnalités qui suppriment des irritants (adieu certaines bibliothèques tierces obligatoires), langage C# toujours plus expressif… Le tout sans révolution brutale : la montée en version devrait être relativement fluide. Que vous soyez un développeur back-end curieux des moindres gains de performances, ou un lead dev prudent qui ne jure que par les LTS stables, .NET 10 a de quoi vous séduire.

Alors, allez-vous migrer ? Si vous cherchez la sécurité et la durabilité, .NET 10 LTS est là pour vous jusqu’en 2028. Si vous aimez les nouveautés, foncez, vous aurez de quoi vous amuser. Dans tous les cas, commencez à évaluer cette version, à faire tourner vos tests unitaires dessus, et préparez sereinement l’avenir de vos applications.

Bonne exploration de .NET 10, et happy coding !

Cet article est sous licence CC BY 4.0 par l'auteur.