Liste de vérification avant de migrer de .NET Framework vers .NET

· Mis à jour le: · · .NET, .NET Framework, C#, Modernisation, Développement Windows, Migration

Télécharger la checklist Excel avec feuilles en japonais et en anglais

Changer le TargetFramework du .csproj en net10.0, mettre à jour quelques paquets NuGet, et si le build passe, c’est terminé.

… si la migration se résumait à cela, ce serait plutôt tranquille. En réalité, c’est rarement aussi simple.

Sur le terrain, les projets .NET Framework accumulent souvent des hypothèses implicites auxquelles on ne pense pas au quotidien : System.Web, WCF, Web Forms, d’anciens packages.config, web.config.install.xdt, des DLL natives, COM / ActiveX, des contrôles tiers qui ne fonctionnent qu’au design time, des hypothèses implicites en x86, des ResX dépendants du designer, d’anciens sérialiseurs, et bien d’autres encore.

C’est pourquoi ce qui compte vraiment dans une migration de .NET Framework vers .NET, c’est l’inventaire réalisé avant d’entrer dans l’implémentation. Si l’on parvient à décomposer les points à traiter avant de commencer, la migration cesse d’être « un gros pari » pour devenir « une liste de tâches à cocher une par une ».

Cet article résume ce qu’il faut vérifier avant de migrer une application métier existante en .NET Framework 4.x vers le .NET actuel. Les cibles principales sont, à peu près, les suivantes :

  • Bibliothèques de classes
  • Applications console
  • Services Windows
  • WinForms / WPF
  • ASP.NET Framework (MVC / Web API / Web Forms)
  • Applications utilisant WCF
  • Applications utilisant EF6

Cet article a été rédigé le 15/03/2026. Les périodes de support et les recommandations des outils officiels évoluent, donc si vous le lisez longtemps après cette date, vérifiez également les informations officielles à jour.

1. D’abord, la conclusion

Commençons par poser les conclusions difficiles à remettre en cause.

  • Nettoyer le côté .NET Framework avant de migrer vient en premier. Le guide officiel de Microsoft recommande lui aussi, avant le portage, de passer à .NET Framework 4.7.2 ou ultérieur, puis de terminer d’abord la conversion en PackageReference, le passage au format SDK-style et la mise à jour des dépendances.
  • La difficulté est déterminée par le modèle applicatif plutôt que par le volume de code. Les bibliothèques de classes et les applications console sont relativement légères, tandis que ASP.NET Framework, Web Forms, les serveurs WCF et WF ont tendance à être lourds.
  • WinForms / WPF peuvent migrer vers .NET tout en restant exclusivement Windows. Se tromper sur ce point, c’est marcher sur la mine classique : avoir migré et découvrir que l’application ne tourne toujours pas dans un conteneur Linux.
  • ASP.NET Framework → ASP.NET Core est, dans les faits, une migration d’architecture. Pour une petite application, il est parfois possible d’y aller d’un coup, mais pour un système de production de grande taille, il est plus sûr de partir du principe d’une migration par étapes.
  • WCF et EF6 peuvent parfois être dissociés de la migration du runtime. Le client WCF dispose de paquets pris en charge pour .NET, et EF6 peut être migré vers EF Core dans un second temps, une fois le passage à .NET moderne effectué.
  • À l’inverse, la création d’AppDomain, .NET Remoting, CAS, COM+, Workflow Foundation et les dépendances à BinaryFormatter sont des signaux rouges. Si vous ne les repérez pas en amont, la charge de travail explosera plus tard.
  • packages.config / install.ps1 / XDT / les ressources du dossier content / les DLL natives / COM / ActiveX / les hypothèses en x86 échouent facilement à l’exécution ou au design time même quand le build passe : il faut donc les passer au crible avant de commencer.
  • À la date de mars 2026, .NET 10 est la version LTS. Pour une nouvelle migration, il est naturel de viser comme point d’arrivée la LTS en cours.
  • Une migration sans tests, sans mesures et sans plan de retour arrière est dangereuse. Migrer est moins un travail d’implémentation qu’un travail consistant à rendre visibles, une à une, les hypothèses de départ.

2. Décider d’abord s’il faut vraiment migrer maintenant

Ce qu’il faut décider en premier, ce n’est pas « comment migrer », mais si cette application doit vraiment être migrée maintenant.

Rester flou sur ce point conduit souvent soit à une migration techniquement correcte mais trop lourde pour l’activité, soit, à l’inverse, à repousser indéfiniment une migration qui serait pourtant clairement justifiée.

2.1 Rester sur .NET Framework est une décision tout à fait envisageable

.NET Framework 4.8.1 continue d’être pris en charge tant qu’il tourne sur une version de Windows elle-même supportée. Autrement dit, ce n’est pas aussi simple que « tout migrer vers .NET moderne immédiatement, sinon c’est le danger ».

Rester comporte toutefois des contraintes bien réelles.

  • Impossible de sortir du tout-Windows
  • Continuer à porter ASP.NET Web Forms et d’anciennes piles serveur
  • Difficile de profiter des gains de performance, des nouvelles fonctionnalités du langage et de l’écosystème des versions récentes de .NET
  • Décalage facile avec les hypothèses actuelles autour du cloud, des conteneurs et de la CI/CD

À l’inverse, si les dépendances suivantes sont fortes, il est raisonnable de rester pour l’instant sur .NET Framework 4.8.1 en exploitation stable, tout en préparant un plan de remplacement sur une autre voie.

  • Un grand nombre d’écrans Web Forms
  • La nécessité de préserver strictement la compatibilité d’un serveur WCF
  • Une dépendance profonde à Workflow Foundation ou à COM+
  • Des composants tiers utilisés au design time non pris en charge par .NET moderne
  • Le contexte métier n’autorise pas de changements de spécification majeurs

2.2 Ce qui change selon l’option choisie

Choix Ce qui s’améliore Ce qui reste / ce que l’on perd Cas adapté
Rester sur .NET Framework 4.8.1 Facile de conserver les actifs existants et d’exploiter de façon stable Exclusivement Windows, ancien modèle applicatif, limites de la modernisation Forte dépendance legacy, priorité donnée à l’activité et à une exploitation stable pour l’instant
Migrer vers .NET moderne en restant sur Windows Le runtime et la chaîne d’outils peuvent être modernisés. Gains importants en performance, en expérience de développement et grâce au format SDK-style Les dépendances aux API Windows subsistent. Pas de portabilité multiplateforme Applications métier WinForms / WPF, services Windows, utilisation d’API Windows
Migrer vers .NET moderne en envisageant Linux / les conteneurs / le cloud à terme Plus de liberté sur les cibles de déploiement. Plus facile de moderniser aussi le modèle d’exploitation Il faut d’abord retirer les API et le modèle applicatif propres à Windows Vous voulez orienter le back-end vers le cloud et moderniser aussi l’infrastructure

Ce qui compte, ce n’est pas de vouloir migrer, mais de décider d’abord où l’on veut atterrir après la migration.

3. Quatre orientations à décider en amont

3.1 La version .NET visée comme point d’arrivée

Au moment de la rédaction, selon la politique de support de Microsoft, .NET 10 est la version LTS. Par ailleurs, .NET 8 LTS et .NET 9 STS doivent tous deux atteindre la fin de leur support le 10/11/2026.

Donc, pour une nouvelle migration depuis .NET Framework, sauf raison particulière, il est naturel de viser la LTS en cours comme point d’arrivée.

Le raisonnement pratique ici est simple.

  • Pour une petite migration que l’on veut boucler rapidement, atterrir directement sur la LTS en cours
  • Même pour un système central destiné à une exploitation de longue durée, la LTS en cours reste la base à privilégier
  • « Rester sur la LTS précédente à cause d’une bibliothèque existante » peut être une raison légitime, mais il faut trancher en regardant concrètement jusqu’à quelle date elle sera maintenue

3.2 Rester exclusivement Windows, ou viser le multiplateforme à terme ?

Cette décision change radicalement les points à examiner.

  • Si vous restez exclusivement sur Windows, vous pouvez suivre la voie réaliste consistant à d’abord moderniser le runtime avec WPF / WinForms et le Windows Compatibility Pack.
  • Si vous visez à terme Linux ou la conteneurisation, il faut inventorier tôt les API liées à Windows telles que System.Drawing.Common, le registre, WMI, EventLog, les services Windows, COM et Office Interop.

Commencer la migration sans avoir tranché ce point conduit tôt ou tard à des discussions qui partent dans tous les sens : « Est-ce que rester fixé sur Windows était vraiment le bon choix ? » « Non, en fait on voulait le faire tourner en conteneur. »

3.3 Tout migrer d’un coup, ou par étapes ?

Il existe globalement trois formes de migration.

  • Une migration globale, proche d’un remplacement sur place (in-place)
  • Une migration en side-by-side, où l’ancien et le nouveau coexistent
  • Une migration incrémentale, route par route ou bibliothèque par bibliothèque

Pour les applications ASP.NET Framework en particulier, le guide de Microsoft recommande explicitement la migration incrémentale (incremental migration). Si vous ne pouvez pas arrêter la production, si le nombre de fonctionnalités est élevé, ou si les dépendances périphériques sont nombreuses, il est plus raisonnable de concevoir dès le départ la migration comme un processus par étapes.

3.4 Ce qu’il faut exclure du périmètre de cette migration

Les migrations échouent souvent parce que l’on essaie d’en faire trop à la fois.

Par exemple, faire tout ce qui suit en même temps tend à devenir très lourd :

  • .NET Framework → .NET
  • ASP.NET Framework → ASP.NET Core
  • EF6 → EF Core
  • Serveurs Windows → conteneurs Linux
  • Changement de l’infrastructure d’authentification
  • Changement de l’infrastructure de journalisation / supervision
  • Migration de la base de données

Bien sûr, tout cela sera peut-être nécessaire un jour. Mais la question de savoir si tout doit être fait en même temps est une autre affaire.

En pratique, séparer les choses de la façon suivante fonctionne mieux :

  1. D’abord moderniser le runtime et la structure du projet
  2. Ensuite migrer le modèle applicatif
  3. Enfin mettre à jour l’ORM, l’authentification, le cloud et la supervision

4. Les fondations à préparer avant de commencer

Le guide de pré-portage de Microsoft est très concret sur le terrain. En résumé, il s’agit de rapprocher, avant la migration, le projet .NET Framework actuel d’un point d’entrée moderne.

4.1 Passer à .NET Framework 4.7.2 ou ultérieur

Le guide officiel recommande de cibler .NET Framework 4.7.2 ou ultérieur avant le portage. La raison est que, même lorsque .NET Standard ne reprend pas telle quelle une API existante, il devient plus facile de se rapprocher d’alternatives plus récentes.

En pratique, il est plus clair de prendre 4.8.1 comme référence si possible.

  • Simple du point de vue du support
  • Facile à traiter comme le point stable final côté .NET Framework
  • Facilite l’adoption d’une politique du type « d’abord nettoyer côté Framework actuel »

Ce que cela change de le faire en premier

  • La gestion des bibliothèques partagées .NET Standard 2.0 se stabilise plus facilement
  • Le bruit provenant de l’ancien runtime peut être réduit en amont
  • Il devient plus facile de déterminer si un problème de compatibilité vient de l’ancienneté du Framework ou du passage à .NET moderne

4.2 Basculer vers PackageReference

Le guide de pré-portage recommande de convertir les références au format PackageReference. Le faire en amont améliore nettement la visibilité sur la gestion des dépendances.

Ce que change le passage à PackageReference

  • Les références de paquets sont regroupées dans le csproj
  • Les dépendances transitives deviennent plus lisibles
  • Les hypothèses de restore s’alignent avec le côté .NET moderne
  • Meilleure compatibilité avec la CLI / la CI

Il y a toutefois des pièges ici.

Pièges classiques

La documentation officielle de NuGet mentionne explicitement les contraintes suivantes pour la migration de packages.config vers PackageReference :

  • La migration intégrée de Visual Studio ne fonctionne pas pour les projets ASP.NET
  • Les paquets dépendant de install.ps1 / uninstall.ps1 peuvent ne pas fonctionner comme prévu
  • Les ressources du dossier content peuvent être ignorées
  • Les transformations XDT telles que web.config.install.xdt ne sont pas appliquées
  • Les paquets dont la disposition des assemblies sous lib est ancienne peuvent mal se résoudre

Autrement dit, il vaut mieux ne pas considérer cela comme un simple changement de format de paquet. L’ASP.NET classique en particulier avait fortement pour habitude de réécrire web.config lors de l’installation d’un paquet NuGet, ce qui fait ressortir facilement des hypothèses implicites lors de la migration.

4.3 Basculer vers le format SDK-style

Le guide de pré-portage recommande également de convertir vers le format de projet SDK-style.

Cela a un impact considérable.

Ce que change le format SDK-style

  • Le csproj devient nettement plus concis
  • Bonne compatibilité avec PackageReference
  • Facilite le multi-targeting
  • Facile à centrer sur une CI/CD basée sur dotnet build / dotnet test / dotnet publish
  • Se rapproche de la configuration côté .NET moderne, réduisant l’écart en fin de parcours

Autrement dit, sauter directement vers .NET moderne en conservant un ancien csproj et une gestion NuGet ancienne produit un écart bien trop important.

4.4 Mettre à jour les dépendances en amont

Toujours conformément au guide officiel, il s’agit de rapprocher les dépendances des dernières versions disponibles, et si possible de versions compatibles .NET Standard.

Pourquoi le faire en amont

  • On sait rapidement si « ce paquet fonctionne sur .NET moderne »
  • Évite que d’anciennes dépendances ne deviennent du bruit
  • Facilite la conversion des bibliothèques partagées en netstandard2.0
  • Permet de concentrer le travail de migration ultérieur sur « le portage du code »

4.5 Vérifier aussi les prérequis des outils officiels

En mars 2026, le centre de gravité des recommandations de Microsoft s’est déplacé vers la modernisation via GitHub Copilot. Plutôt que de s’appuyer uniquement sur les outils d’assistance à la migration traditionnels, il est plus réaliste de considérer cela comme un flux d’assistance complet couvrant l’évaluation, la planification, les corrections de code et la validation.

La documentation actuelle suppose toutefois Visual Studio 2026 ou une version de la lignée Visual Studio 2022 encore supportée, GitHub Copilot, et du code C#.

Pourquoi cette vérification est nécessaire

  • Ce que l’on peut attendre des outils officiels change
  • Permet d’aligner les hypothèses de l’équipe concernant l’IDE, les agents de build et les extensions
  • Permet de décider de ne pas trop compter sur l’automatisation pour les solutions VB.NET

Les projets mêlant du VB.NET ne sont pas rares. Il vaut donc la peine de vérifier dès le départ jusqu’où les derniers outils officiels peuvent réellement aider.

5. Estimer la difficulté selon le type de projet

On parle souvent de la migration « de .NET Framework vers .NET » comme d’un tout, mais en réalité, chaque type de projet est un jeu différent.

5.1 Un aperçu global de la difficulté

Type Difficulté Points principaux
Bibliothèque de classes Faible à moyenne Compatibilité des API, dépendances, découpage des cibles
Console / traitement par lot / certains services Windows Faible à moyenne Mode de distribution, dépendances natives, configuration
WinForms / WPF Moyenne Reste exclusivement Windows ; designer, UI tierces, environs de BinaryFormatter
ASP.NET MVC / Web API Moyenne à élevée Migration du modèle applicatif vers ASP.NET Core, authentification, session, configuration, DI
ASP.NET Web Forms Élevée Grand écart de modèle d’écran ; suppose le remplacement de la couche UI
Client WCF Moyenne Remplacement de paquets, contrats, configuration
Serveur WCF Élevée CoreWCF ou refonte en gRPC / API HTTP
EF6 → EF Core en même temps Élevée ORM totalement différent, différences de comportement, historique de migrations

5.2 Pour les bibliothèques de classes, la clé est de bien découper la « frontière partagée »

Les bibliothèques de classes sont relativement faciles à migrer. Mais cela n’est vrai que lorsque la bibliothèque est réellement isolée comme une bibliothèque devrait l’être.

La difficulté augmente en présence de dépendances comme les suivantes :

  • Toucher à System.Web
  • Lire directement HttpContext.Current
  • Exposer des types WPF / WinForms dans l’API publique
  • Dépendre fortement d’API Windows telles que le registre, WMI, EventLog
  • Dépendre d’AppDomain ou de Remoting

Une manière simple de voir les choses : si l’on peut extraire uniquement la logique métier, c’est léger ; si la bibliothèque a englouti le modèle applicatif, c’est lourd.

5.3 WinForms / WPF migrent facilement, mais restent exclusivement Windows

WinForms et WPF peuvent être migrés vers .NET. Mais dans les deux cas, ils restent des frameworks exclusivement Windows.

Se tromper sur ce qu’il faut en attendre ici est dangereux.

  • Ce qui s’améliore
    • Bénéficier du runtime, du langage et du format SDK-style de .NET moderne
    • Facile de rapprocher la CI/CD et la gestion des paquets des pratiques actuelles
    • Facile d’obtenir certains gains de performance et de maintenabilité
  • Ce qui ne change pas
    • Rester exclusivement Windows
    • Les problèmes de compatibilité des contrôles UI et des composants design-time subsistent
    • Les problèmes liés à ActiveX / COM / DLL natives ne disparaissent pas

Par ailleurs, il arrive que WinForms / WPF nécessitent de vérifier l’impact de BinaryFormatter. En particulier lorsque des types personnalisés interviennent dans le presse-papiers, le glisser-déposer, les ResX ou la sérialisation au design time, le problème a tendance à ressortir lorsqu’on relève la cible vers .NET 9 ou ultérieur.

5.4 ASP.NET Framework relève d’une « migration du modèle applicatif », pas d’une « migration du runtime »

La migration d’ASP.NET Framework vers ASP.NET Core est explicitement qualifiée de non-trivial dans le guide de Microsoft. Ce n’est pas simplement parce que les noms d’API changent, mais parce que l’architecture sous-jacente est différente.

Les différences apparaissent principalement autour des éléments suivants :

  • Hosting model
  • Middleware pipeline
  • Request processing model
  • Session / Cache
  • Authentication / Authorization
  • Configuration
  • Dependency Injection
  • Logging / Monitoring

Pour une application ASP.NET Framework, voici ce qu’il convient de vérifier en premier :

  • Quelles routes / quels endpoints peuvent être migrés en premier
  • Peut-on retirer la dépendance à System.Web des bibliothèques partagées
  • Comment harmoniser l’authentification, la session, la gestion des exceptions et la journalisation
  • Faut-il migrer par étapes sans arrêter la production

Pour les applications de grande taille en particulier, il est plus réaliste de partir du principe d’une migration incrémentale (incremental migration) dès le départ.

5.5 Pour Web Forms, commencer par « décomposer les responsabilités », pas par « migrer les actifs »

Web Forms n’est pas le même modèle applicatif qu’ASP.NET Core. Pour l’estimation, il est donc plus sûr de ne pas partir du principe que les écrans peuvent être repris tels quels.

En pratique, on commence souvent par la décomposition suivante :

  • Séparer la logique d’écran de la logique métier
  • Décomposer les responsabilités enfouies dans Page / UserControl / ViewState
  • Extraire la logique métier et l’accès aux données vers des bibliothèques partagées
  • Reconstruire l’UI selon un autre modèle : Razor Pages, MVC, Blazor, etc.

Autrement dit, pour un projet Web Forms, l’existence d’un plan de décomposition des responsabilités compte davantage que la migration du runtime elle-même.

5.6 Distinguer le client WCF du serveur WCF

Mieux vaut ne pas mettre les deux dans le même panier.

Client WCF

Le client WCF dispose de paquets NuGet pris en charge pour .NET moderne. Donc, si l’on se limite au côté appelant de WCF, la charge peut être moins lourde qu’il n’y paraît.

Serveur WCF

Héberger un service WCF, en revanche, est une tout autre affaire. Le guide de Microsoft présente globalement deux voies de modernisation :

  • Utiliser CoreWCF pour préserver la compatibilité avec les clients existants
  • Basculer vers une pile RPC / HTTP moderne telle que gRPC

Notez que CoreWCF ne reprend pas la totalité de WCF telle quelle : c’est un sous-ensemble. Il convient bien pour préserver la compatibilité avec les clients existants, mais des modifications de code et des tests sont incontournables.

6. Recenser les technologies indisponibles sur .NET ou source de blocages fréquents

C’est un point à traiter absolument avant de commencer. Microsoft tient une liste des technologies disponibles sur .NET Framework mais indisponibles sur .NET 6+.

6.1 Technologies qui deviennent souvent des signaux rouges

Technologie État sur .NET Comment l’aborder
Création d’AppDomain, comme AppDomain.CreateDomain Non prise en charge Envisager l’isolation via des processus séparés / des conteneurs / AssemblyLoadContext
.NET Remoting Non pris en charge Refonte autour de l’IPC, HTTP, gRPC, sockets, pipes, etc.
CAS / Security Transparency Non pris en charge comme frontière de sécurité Envisager la séparation via l’OS / les conteneurs / les privilèges
System.EnterpriseServices (COM+) Non pris en charge Isoler et remplacer les conceptions reposant sur COM+
Workflow Foundation Non pris en charge À estimer séparément, en tenant compte d’alternatives comme CoreWF
Serveur WCF Non disponible tel quel en natif Choisir entre CoreWCF ou gRPC
BinaryFormatter Sur .NET 9+, l’implémentation lève systématiquement une exception Migrer le sérialiseur ; auditer les ResX / le presse-papiers / le glisser-déposer

6.2 AppDomain : « certaines API subsistent, mais la création reste un problème à part »

Le sujet AppDomain est un peu délicat. Une partie de la surface d’API subsiste bien sur .NET, mais l’usage consistant à créer un nouvel AppDomain pour isoler du code n’est pas pris en charge.

Une refonte est donc nécessaire si AppDomain était utilisé dans les buts suivants :

  • Isolation de plugins
  • Déchargement de code chargé dynamiquement
  • Isolation de code partiellement fiable
  • Séparation temporaire d’environnements d’exécution

Avant de migrer, il ne s’agit pas seulement de vérifier si le mot AppDomain apparaît, mais de comprendre à quoi AppDomain servait réellement.

6.3 Remoting est « plus profond qu’il n’y paraît »

Remoting est concerné, bien sûr, mais des délégués asynchrones comme les appels BeginInvoke() / EndInvoke() sur un délégué peuvent aussi entrer dans le périmètre concerné. Ce n’est pas Remoting à proprement parler, mais ce n’est pas pris en charge sur .NET moderne, il faut donc le recenser avant de migrer.

Il est donc plus sûr d’inclure aussi ces éléments dans vos recherches :

  • System.Runtime.Remoting
  • MarshalByRefObject
  • RealProxy
  • BeginInvoke( / EndInvoke(

6.4 BinaryFormatter ressurgit brutalement selon la version cible

Plus une base de code est ancienne, plus il est probable que BinaryFormatter y soit utilisé « sans que personne n’en ait vraiment conscience ».

  • Données persistées
  • Cache
  • Stockage de session
  • État des plugins
  • Presse-papiers / glisser-déposer
  • ResX
  • Environs du designer WinForms / WPF

À partir de .NET 9, l’implémentation de BinaryFormatter n’est plus incluse dans le runtime, et l’API lève systématiquement PlatformNotSupportedException. Ce n’est donc pas un sujet à traiter « plus tard », mais un point à auditer dès que la version cible est fixée.

6.5 Termes à rechercher (grep) en priorité

Avant de commencer, il suffit de lancer une recherche sur l’ensemble de la solution avec les termes suivants pour que la situation devienne bien plus claire.

System.Web
HttpContext.Current
System.Runtime.Remoting
MarshalByRefObject
AppDomain
BinaryFormatter
ServiceHost
ChannelFactory
System.EnterpriseServices
Workflow
packages.config
web.config.install.xdt
install.ps1
DllImport
AxInterop
Microsoft.Office.Interop

Trouver ne serait-ce qu’un seul de ces termes ne signifie pas un échec immédiat. C’est une carte permettant de savoir ce qui peut migrer par la voie standard et ce qui relève d’une voie à part.

7. Décider jusqu’où accepter une dépendance exclusive à Windows

Un malentendu fréquent lors d’une migration est de croire que « passer à .NET rend automatiquement l’application multiplateforme ». Cette magie n’existe pas. Si l’application est profondément liée à Windows, elle reste tout simplement exclusivement Windows après la migration.

7.1 Migrer en restant exclusivement Windows est une option tout à fait réaliste

Microsoft propose le Windows Compatibility Pack, un moyen d’utiliser depuis .NET moderne de nombreuses API orientées Windows : le registre, WMI, EventLog, les services Windows, Directory Services, et bien d’autres.

Son existence compte beaucoup en pratique.

  • On veut d’abord passer à .NET moderne
  • Mais on ne quitte pas Windows pour l’instant
  • Donc on veut accepter provisoirement les dépendances aux API Windows

Dans ce genre de contexte, c’est une option solide.

Le premier objectif d’une migration n’a donc pas forcément besoin d’être la portabilité multiplateforme.

7.2 Mais les API exclusivement Windows sont aussi « une dette qui se rappellera à vous plus tard »

L’existence du Windows Compatibility Pack ne met pas tout à l’abri pour autant.

  • Vous voulez déployer en conteneur Linux
  • Vous voulez faire tourner l’application sous Kubernetes
  • Vous voulez que les développeurs macOS / Linux exécutent le même build
  • Vous voulez réduire à terme le nombre de VM Windows dans le cloud

Si vous avez ce genre d’objectifs, il est préférable de rendre visibles dès maintenant les dépendances aux API Windows.

7.3 System.Drawing.Common est un cas particulièrement mal compris

System.Drawing.Common est, à partir de .NET 6, une bibliothèque exclusivement Windows. Si vous avez du code qui l’utilise pour du traitement d’image ou du rendu de texte, il faut d’abord décider de la direction à prendre.

  • Continuer à exploiter sur Windows ?
  • Ou vouloir le faire tourner un jour sur Linux / macOS ?

Dans le premier cas, laisser les choses en l’état pour l’instant peut convenir. Dans le second, il faut inclure dès le départ dans le plan de migration un remplacement par des bibliothèques comme SkiaSharp ou ImageSharp.

7.4 Signes typiques révélant un ancrage à Windows

En présence de références ou d’API comme celles-ci, il est plus sûr d’estimer en partant du principe que la migration restera exclusivement Windows, au moins dans un premier temps.

  • Microsoft.Win32.Registry
  • System.Management
  • System.Diagnostics.EventLog
  • System.ServiceProcess
  • System.DirectoryServices
  • System.Drawing
  • DllImport / P/Invoke
  • Références COM
  • AxInterop.*
  • Microsoft.Office.Interop.*

8. La manière de découper les bibliothèques partagées change la difficulté

Pour les solutions de grande taille, il n’est pas exagéré de dire que le succès de la migration se joue sur la façon dont sont découpées les bibliothèques partagées.

8.1 Commencer par classifier

Il est plus simple d’organiser les bibliothèques en les répartissant en trois grandes catégories.

  1. La logique métier pure / la logique de domaine
  2. Une couche intermédiaire légèrement dépendante du modèle applicatif
  3. Une couche étroitement liée à l’UI / au Web / aux API Windows

Parmi ces trois, c’est la catégorie 1 qu’il faut migrer en premier.

  • Calculs
  • Évaluation de règles
  • DTO / contrats
  • Services de domaine
  • Transformations de données simples

Si l’on parvient à l’extraire proprement, la difficulté chute nettement.

8.2 netstandard2.0 reste un pont valable

Selon les recommandations de Microsoft, pour une bibliothèque partagée devant aussi coexister avec le côté .NET Framework, il est de base d’envisager d’abord .NET Standard 2.0.

Deux points importent ici.

  • .NET Framework ne prend pas en charge .NET Standard 2.1
  • Si vous voulez qu’une bibliothèque partagée soit référencée à la fois par l’ancien et le nouveau code, 2.0 tend à être la solution réaliste

8.3 Ce que change le passage à netstandard2.0

Politique Ce qui change Cas adapté Points de vigilance
Conversion en netstandard2.0 Facile à référencer à la fois depuis l’ancien et le nouveau code Logique métier pure, contrats communs, utilitaires Les API propres à un modèle applicatif ne peuvent pas y figurer
Multi-target (ex. net48;net10.0) Conserve le code commun tout en gérant des différences par environnement Bibliothèques avec quelques différences d’environnement Plus de branches conditionnelles et de gestion de build
Passage direct à net10.0 uniquement Le plus propre à long terme Nouvelles couches ne nécessitant pas de coexistence ancien/nouveau Ne peut plus être référencé depuis .NET Framework

8.4 Le mode de compatibilité n’est pas une solution miracle

.NET Standard 2.0 dispose d’un mode de compatibilité permettant de référencer des bibliothèques .NET Framework. Ce n’est toutefois pas une magie qui ferait fonctionner n’importe quoi de façon transparente.

Par exemple, une bibliothèque reposant sur des API propres à un modèle applicatif comme WPF reste tout simplement difficile. Autrement dit, même en parlant de « bibliothèque partagée », il est essentiel de se limiter aux responsabilités réellement partageables.

8.5 Pour les bibliothèques liées à ASP.NET, tout se joue sur la capacité à retirer System.Web

Lors d’une migration incrémentale d’ASP.NET Framework, avoir des bibliothèques partagées accrochées directement à HttpContext.Current ou à System.Web est très pénible.

Les stratégies de base dans ce cas sont l’une des suivantes :

  • Repousser la dépendance à System.Web en dehors de l’interface
  • Faire recevoir les informations issues de HttpContext sous forme de DTO
  • Utiliser des adaptateurs pendant la période de transition
  • Si cela reste impossible, retirer la dépendance progressivement via le multi-targeting

8.6 Migrer les bibliothèques en commençant par les feuilles (leaf-first)

Le guide de migration incrémentale d’ASP.NET indique explicitement de faire migrer les bibliothèques de support en postorder depth-first, c’est-à-dire en partant des feuilles.

Ce principe est très efficace bien au-delà du Web, pour des solutions générales aussi.

  • Comme les dépendances sont migrées en premier, les couches supérieures deviennent plus lisibles
  • Facilite la localisation des problèmes de compatibilité
  • Facilite les tests bibliothèque par bibliothèque

9. Faire l’inventaire de NuGet, des dépendances externes et des composants tiers

Bâcler cette étape est ce qui fait le plus mal en fin de migration.

9.1 Les dépendances s’organisent mieux en quatre catégories

  1. Paquets NuGet publics
  2. Paquets privés internes / bibliothèques internes
  3. Références DLL locales
  4. COM / ActiveX / DLL natives / SDK

Ne regarder que la catégorie 1 ne suffit pas. Ce qui est vraiment dangereux, ce sont les catégories 3 et 4.

9.2 Ce qu’il faut vérifier pour chaque dépendance

Pour chaque dépendance, vérifiez au minimum ce qui suit.

  • Cible-t-elle .NET moderne ?
  • Prend-elle en charge PackageReference ?
  • Fonctionne-t-elle correctement en SDK-style ?
  • Y a-t-il des contraintes x86 / x64 / ARM64 ?
  • Dépend-elle d’outils design-time ou d’extensions Visual Studio ?
  • Suppose-t-elle des scripts d’installation ou des transformations de configuration ?
  • Le support est-il toujours actif ?

9.3 Estimer à part les composants UI, reporting et design-time tiers

Pour les migrations WinForms / WPF / ASP.NET, ce point pèse lourd.

  • Grilles
  • Moteurs de reporting
  • Composants de génération de PDF
  • Composants graphiques
  • Bibliothèques UI intégrées au designer
  • Wrappers ActiveX

Ces éléments engagent non seulement le runtime mais aussi le support au design time. Une estimation de migration qui ne regarde que « est-ce que ça compile » passera tout simplement à côté.

9.4 Toujours vérifier les DLL natives et la bitness

Même si le projet semblait tourner en AnyCPU à l’époque de .NET Framework, il peut en réalité dépendre de choses comme :

  • COM figé en x86
  • ActiveX exclusivement 32 bits
  • Une version spécifique du runtime VC++
  • Des DLL natives signées

Ce ne sont pas des problèmes qui apparaissent soudainement avec le passage à .NET moderne : ce sont des contraintes qui existaient déjà et qui refont simplement surface. C’est précisément pour cela qu’il vaut la peine de les rendre visibles avant la migration.

10. Traiter EF6, les sérialiseurs et le domaine des données comme des problèmes distincts

La migration du runtime et la refonte de l’accès aux données ou de la sérialisation fonctionnent mieux lorsqu’elles sont traitées comme des problèmes distincts, autant que possible.

10.1 EF6 → EF Core n’est pas une mise à niveau directe

Le guide EF de Microsoft indique lui aussi qu’EF Core est une réécriture totale d’EF6, sans chemin de mise à niveau direct.

Pour une application utilisant EF6, l’ordre suivant est donc réaliste :

  1. D’abord passer à .NET moderne
  2. Faire tourner l’application en conservant EF6 si nécessaire
  3. Migrer ensuite vers EF Core dans le cadre d’un projet séparé

Ne pas combiner la migration du runtime et la migration de l’ORM. Cela suffit déjà à réduire considérablement la difficulté.

10.2 Ce que change le fait de conserver EF6

  • Avantages
    • L’écart au niveau de la couche d’accès aux données peut être reporté
    • Permet de se concentrer sur la migration de la logique métier et du modèle applicatif
    • Les « différences de comportement d’EF Core » n’interfèrent pas
  • Points de vigilance
    • Pour les nouveaux développements, EF Core reste la solution à privilégier
    • L’usage du Designer EF6 / d’EDMX comporte des contraintes spécifiques

10.3 Pour EF6 basé sur EDMX, regarder jusqu’au « design time »

La documentation d’EF6 précise que le EF Designer n’est pas directement pris en charge dans les projets .NET / .NET Standard ni dans les projets .NET Framework au format SDK-style.

Pour une application basée sur EDMX, il faut distinguer ces trois points :

  • Fonctionne-t-elle à l’exécution ?
  • Le Designer est-il utilisable ?
  • Comment gérer le code généré ?

Si vous utilisez EDMX de façon intensive, il est plus sûr d’inclure ce point dans l’estimation dès le départ.

10.4 BinaryFormatter et les sérialisations maison deviennent facilement des « dépendances cachées »

Les sérialiseurs sont faciles à manquer avec une simple recherche dans le code.

  • Formats de persistance
  • Messagerie
  • Cache
  • Anciens contrats WCF / SOAP
  • ResX
  • Presse-papiers / glisser-déposer

Ce domaine engage aussi la compatibilité des données. Autrement dit, il ne suffit pas de vérifier « est-ce que ça build », il faut aussi vérifier si les anciennes données peuvent encore être lues.

11. Inclure la configuration, la distribution, l’exploitation et la CI/CD dans le périmètre de la migration

Le périmètre de la migration ne se limite pas au code source.

11.1 Fichiers de configuration

Côté .NET Framework, app.config / web.config peuvent porter un nombre considérable d’éléments.

  • Chaînes de connexion
  • Sections de configuration personnalisées
  • Configuration des endpoints WCF
  • Redirections de binding
  • Diagnostics
  • Divers réglages ASP.NET
  • Résultats des transformations appliquées à l’installation des paquets

Côté .NET moderne, la façon de stocker et de charger la configuration change dans certains cas. « La configuration, on verra plus tard » est donc dangereux.

La première chose à faire est l’inventaire de la configuration.

  • Ce qui se trouve dans les fichiers de configuration
  • Ce qui est indispensable au démarrage de l’application
  • Ce qui relève de différences d’environnement
  • Ce qui a été injecté automatiquement par NuGet ou un installateur

11.2 Mode de distribution

Examinez aussi la forme de distribution avant de commencer.

  • Sous IIS ?
  • Un service Windows ?
  • Une tâche planifiée ?
  • ClickOnce / MSI / un installateur maison ?
  • Suppose-t-il des serveurs on-premise ?
  • Self-contained ou framework-dependent, lequel convient le mieux ?

Même si l’exécutable lui-même migre correctement, vous vous retrouverez bloqué en fin de parcours si le mécanisme de distribution et de démarrage repose encore sur d’anciennes hypothèses.

11.3 Journalisation, supervision et procédures d’exploitation

Le volet exploitation est également facile à négliger.

  • Suppose-t-il le journal d’événements Windows ?
  • Des compteurs de performance sont-ils surveillés ?
  • Une supervision basée sur WMI ?
  • Les comptes de service et les privilèges sont-ils figés ?
  • Les journaux supposent-ils une sortie vers un fichier local ?

Il est tout à fait courant que le code fonctionne après la migration, mais que l’exploitation ne suive plus.

11.4 CI/CD et agents de build

Avant de migrer, vérifiez également ce qui suit.

  • Le SDK .NET requis peut-il être installé sur les agents de build ?
  • Que faire des pipelines supposant nuget.exe / msbuild.exe ?
  • Faut-il basculer vers une base CLI dotnet ?
  • Comment mettre à jour les jobs d’exécution des tests, de couverture de code et de publication ?
  • Les modèles internes ou les pipelines réutilisables supposent-ils encore l’ancien format ?

« Ça marche sur mon poste, mais la CI plante » est un grand classique des migrations.

12. Une façon réaliste de mener la migration

En tenant compte de tout ce qui précède, l’approche réaliste se ramène généralement à la forme suivante.

12.1 D’abord mettre de l’ordre côté Framework actuel

  1. Passer à .NET Framework 4.7.2 ou ultérieur, idéalement 4.8.1
  2. Mettre à jour les dépendances
  3. Revoir packages.config
  4. Basculer vers PackageReference et le format SDK-style dans la mesure du possible
  5. Confirmer que l’application actuelle fonctionne bien dans cet état

Faire seulement cela réduit déjà considérablement l’écart en fin de parcours.

12.2 Sauver d’abord les bibliothèques partagées

Ensuite, rapprochez la logique métier et les contrats communs de netstandard2.0 ou du multi-targeting. L’ordre de migration suit, en règle générale, le principe leaf-first.

12.3 Adapter la stratégie de l’application elle-même selon le modèle applicatif

  • Bibliothèques de classes / console / certains services Relativement simple à mener
  • WinForms / WPF Moderniser en restant exclusivement Windows
  • ASP.NET MVC / Web API D’un seul coup si petit, par étapes si lourd
  • Web Forms Partir du principe d’un remplacement des écrans, en extrayant d’abord la logique partagée
  • Serveurs WCF Décider d’abord entre conserver CoreWCF ou refondre en gRPC

12.4 Respecter le principe « ne pas tout faire en même temps »

Les combinaisons à éviter particulièrement sont les suivantes.

  • Migration du runtime + remplacement complet de l’ORM
  • Migration du runtime + changement de l’infrastructure d’authentification
  • Migration du runtime + migration cloud complète
  • Migration du runtime + changement de l’infrastructure de supervision
  • Migration du runtime + refonte du framework UI

Même si tout est nécessaire, ne pas empiler ces chantiers dans le même sprint fonctionne généralement mieux.

12.5 Prendre des tests et des lignes de base avant d’agir

Voici, au minimum, ce qu’il faut avoir en place avant de bouger :

  • Tests unitaires
  • Tests d’intégration des principaux flux métier
  • Une vérification de type snapshot des écrans / API représentatifs
  • Une ligne de base de performance
  • Une méthode de vérification des journaux principaux
  • Une procédure de retour arrière

Avancer dans un état où l’on ne peut pas identifier « ce qui a cassé » après la migration est particulièrement risqué.

13. Liste de vérification avant de commencer

Voici cette liste sous une forme prête à coller directement dans votre outil de gestion de projet.

13.1 Orientations

  • Vous pouvez énoncer en une phrase pourquoi vous migrez
  • Le point d’arrivée est décidé : .NET moderne exclusivement Windows ou portabilité multiplateforme à terme
  • La version .NET cible est décidée
  • Ce qui est exclu du périmètre (passage à EF Core, refonte de l’authentification, migration cloud complète, etc.) est décidé

13.2 Préparation du côté .NET Framework actuel

  • Passage à .NET Framework 4.7.2 ou ultérieur, idéalement 4.8.1, effectué
  • Dépendances mises à jour vers les versions récentes
  • Présence de packages.config vérifiée
  • Faisabilité du passage à PackageReference vérifiée
  • Faisabilité du passage au format SDK-style vérifiée
  • L’application actuelle build, démarre et passe les tests dans cet état

13.3 Type d’application et choix technologiques

  • Difficulté répartie par type : bibliothèque de classes / desktop / Web / WCF, etc.
  • Compris que WinForms / WPF resteront exclusivement Windows
  • Compris qu’ASP.NET Framework implique une migration du modèle applicatif vers ASP.NET Core
  • Remplacement de la couche UI de Web Forms inclus dans l’estimation
  • Client et serveur WCF évalués séparément

13.4 Technologies non prises en charge / API à surveiller

  • Dépendances à AppDomain recensées
  • Remoting / MarshalByRefObject / BeginInvoke / EndInvoke recensés
  • CAS / Security Transparency / COM+ / WF recensés
  • Dépendances à BinaryFormatter recensées
  • Dépendances à System.Web recensées

13.5 Dépendances exclusivement Windows

  • Utilisation du registre, de WMI, d’EventLog, des services Windows, de Directory Services recensée
  • Utilisation de System.Drawing.Common recensée
  • COM / ActiveX / Office Interop / P/Invoke / DLL natives recensés
  • Contraintes x86 / x64 / ARM64 vérifiées

13.6 Bibliothèques partagées et accès aux données

  • Bibliothèques partagées classées entre logique métier et couches étroitement liées au modèle applicatif
  • Éléments pouvant passer en netstandard2.0 recensés
  • Bibliothèques nécessitant du multi-targeting recensées
  • Décidé si le runtime peut être migré en premier en conservant EF6
  • Dépendances à EDMX / au Designer vérifiées

13.7 Exploitation et build

  • Inventaire des fichiers de configuration réalisé
  • Mode de distribution vérifié (IIS / service / MSI / ClickOnce, etc.)
  • Hypothèses de journalisation / supervision / privilèges / compte d’exécution vérifiées
  • Besoin de mise à jour de la CI/CD et des agents de build vérifié
  • Procédure de retour arrière rédigée

14. Conclusion

Ce qui compte dans une migration de .NET Framework vers .NET, ce n’est pas tant « avec quelle commande migrer » que de discerner, avant de commencer, ce qui peut passer tel quel et ce qui relève d’un problème à part.

Si l’on devait se limiter à l’essentiel, ce serait ces six points :

  • Nettoyer le côté .NET Framework avant de migrer
  • Répartir la difficulté selon le modèle applicatif
  • Recenser en premier les technologies indisponibles
  • Décider jusqu’où accepter une dépendance exclusive à Windows
  • Décider comment découper les bibliothèques partagées
  • Ne pas empiler ORM, authentification et migration cloud en même temps

La précision de l’estimation d’une migration se joue en grande partie dès la première semaine. Autrement dit, si vous parvenez à clarifier les points en jeu pendant cette semaine, la suite pourra se rapprocher d’un développement assez ordinaire.

« Essayons d’abord de passer à net10.0 » n’est pas une mauvaise idée en phase d’exploration. Mais pour une migration en production, il y a des points à examiner avant cela. C’est précisément ce que cet article a cherché à clarifier.

15. Références

Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.

Ces pages replacent le sujet dans un contexte plus large de services et de décisions.

Cet article est directement lié aux services suivants.

Conseil technique et revue de conception

Si vous souhaitez clarifier avant de commencer le périmètre de la migration, la manière de découper une migration par étapes, et jusqu'où accepter une dépendance exclusive à Windows, ce sujet se prête bien à une consultation technique ou une revue de conception.

Questions fréquentes

Questions souvent posées lors d’une consultation sur le sujet de cet article.

Que dois-je faire avant de migrer de .NET Framework vers .NET ?
Commencez par nettoyer le côté .NET Framework. Le guide officiel de Microsoft recommande lui aussi, avant le portage, de passer à .NET Framework 4.7.2 ou ultérieur (en pratique 4.8.1 est la base la plus claire), de convertir les références en PackageReference, de basculer vers des projets au format SDK-style et de mettre à jour les dépendances vers les dernières versions disponibles. Faire cela en premier réduit fortement l'écart lors de la phase suivante, et permet de distinguer plus facilement si un problème de compatibilité vient de l'ancienneté du Framework ou du passage à .NET moderne. Confirmez également que l'application actuelle build, démarre et passe les tests dans cet état.
Quelles technologies de .NET Framework ne fonctionnent pas sur .NET moderne ?
Les signaux rouges sont la création d'AppDomain (comme AppDomain.CreateDomain), .NET Remoting, Code Access Security, System.EnterpriseServices (COM+), Workflow Foundation, et l'hébergement natif de serveur WCF. BinaryFormatter mérite une attention particulière : à partir de .NET 9, son implémentation lève systématiquement PlatformNotSupportedException, et il se cache dans les données persistées, les caches, le presse-papiers et le glisser-déposer, les ResX, ainsi que la sérialisation du designer WinForms/WPF. Pour les serveurs WCF, les voies possibles sont CoreWCF (un sous-ensemble préservant la compatibilité côté client) ou une refonte autour de gRPC ou d'API HTTP.
Mon application deviendra-t-elle multiplateforme après une migration vers .NET ?
Pas automatiquement. WinForms et WPF migrent vers .NET moderne mais restent des frameworks exclusivement Windows, et System.Drawing.Common est une bibliothèque exclusivement Windows à partir de .NET 6. Les dépendances liées à Windows telles que le registre, WMI, EventLog, les services Windows, COM, Office Interop et P/Invoke vous suivent après la migration. Migrer en restant exclusivement Windows est tout à fait réaliste — le Windows Compatibility Pack existe précisément pour cela — mais si les conteneurs Linux sont un objectif futur, il faut inventorier tôt ces API liées à Windows et prévoir des remplacements comme SkiaSharp ou ImageSharp pour le code d'imagerie.
Faut-il migrer EF6 vers EF Core en même temps que la migration du runtime ?
Non. EF Core est une réécriture totale d'EF6, sans chemin de mise à niveau direct, donc combiner la migration de l'ORM avec la migration du runtime augmente nettement la difficulté. L'ordre réaliste consiste à passer d'abord à .NET moderne, à conserver EF6 si nécessaire, puis à migrer vers EF Core dans le cadre d'un projet séparé. Le même principe s'applique plus largement : évitez d'empiler la migration du runtime avec un changement d'authentification, une migration cloud, un changement de supervision ou une refonte du framework UI dans le même effort, même si tout cela finit par être nécessaire.

Profil de l’auteur

Page de présentation de l’auteur de l’article.

Go Komura

Représentant de KomuraSoft LLC

Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.

Retour au blog