
Faut-il s’en occuper tout de suite ?
Ça n’est pas urgent, mais on peut préparer le terrain. Le point important à souligner est qu’une migration vers un framework plus récent nécessite la réécriture de l’interface : Web Forms repose sur System.Web, dont l’essentiel n’existe pas dans ASP.NET Core ni dans le .NET moderne (.NET Core et .NET 5 et suivants).
Tout dépend de la version de .NET Framework utilisée par votre application. Les 4.7 à 4.8.1 suivent le cycle de vie du Windows qui les exécute. Concrètement : tant que votre OS est supporté et à jour, les correctifs de sécurité sont appliqués. La date à vérifier est la fin de support de ce Windows.
Attention en revanche aux versions suivantes :
- les 4.5.2, 4.6 et 4.6.1 ne sont plus supportées depuis avril 2022.
- la 4.6.2 arrive en fin de support le 12 janvier 2027.
Pour ces versions, la suite est de passer en 4.8, ou en 4.8.1 si le Windows le permet. Cela règle la question du support tant que le Windows est lui-même supporté, sans migrer vers un .NET moderne.
Les besoins qui requièrent une migration sont l’hébergement sur une autre plateforme que Windows, ou une évolution lourde, ou l’utilisation d’une dépendance tierce qui ne suit plus .NET Framework.
Qu’est-ce qui coince réellement ?
Afin de chiffrer une quelconque migration, il est nécessaire de lister les composants de votre application. Voici un exemple de grille qui permet d’évaluer la charge :
| Page | Connexion | Session | Logique dans la page | ViewState, UpdatePanel | Contrôles tiers | Évolution prévue | Piste |
|---|---|---|---|---|---|---|---|
| Aide.aspx | non | aucune | non | non | non | non | première route : peu visitée, sans état |
| Recherche.aspx | oui | lit le dossier ouvert | oui | UpdatePanel | grille | oui | sortir session et logique, voir le fournisseur de la grille, puis Blazor |
| Dossier.aspx | oui | lit et écrit le dossier en cours | oui | non | non | oui | sortir la session, sinon Razor Pages |
| Editions.aspx | oui | aucune | non | non | générateur de rapports | non | attendre, voir avec le fournisseur |
La colonne « Évolution prévue » sert à choisir les pages qui valent la peine d’être migrées, la colonne « Piste » à noter la première action pour chacune. Aide.aspx fait exception : c’est la page pilote, qui sert à valider le montage.
Il faudra ensuite relever les bibliothèques utilisant HttpContext.Current, les HttpModules et enfin les évènements du Global.asax. Les deux derniers seront transformés en middlewares ou en code de démarrage de l’application.
Que puis-je entreprendre sans toucher aux écrans ?
Il est possible d’avancer sur deux axes sans modifier les pages .aspx. Seuls le code-behind et les fichiers de projet changent.
1. Le premier est la réduction de la dette. Au programme :
- Mise à jour des dépendances
- Correction des warnings
- Suppression du code mort
- Conversion des bibliothèques de classes utilisées par les pages à migrer au format SDK-style :
Bibliothèque de classes au format SDK-style
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net10.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup>
</Project>
2. Sortir la logique métier du code-behind
Le modèle Web Forms encourage à stocker la logique métier dans chaque page. Il est donc nécessaire de la déplacer dans une bibliothèque qui pourra être utilisée par les deux applications pendant la transition. Ça donne l’occasion de la couvrir par des tests, qui limitent le risque de régression.
Concernant la session, on la cache derrière une interface.
Avant : tout est dans la page
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var clientId = (int)Session["ClientId"];
var commandes = new CommandeRepository().ParClient(clientId);
GridCommandes.DataSource = commandes.Where(c => !c.Archivee).ToList();
GridCommandes.DataBind();
}
}
Après : une bibliothèque partagée par les deux applications
public interface IContexteClient
{
int ClientId { get; }
}
public class CommandesService
{
private readonly IContexteClient _contexte;
private readonly ICommandeRepository _commandes;
public CommandesService(IContexteClient contexte, ICommandeRepository commandes)
{
_contexte = contexte;
_commandes = commandes;
}
public IReadOnlyList<Commande> CommandesEnCours() =>
_commandes.ParClient(_contexte.ClientId)
.Where(c => !c.Archivee)
.ToList();
}
Côté Web Forms : le contexte lu dans la session, la page qui affiche
public class ContexteClientWebForms : IContexteClient
{
public int ClientId => (int)HttpContext.Current.Session["ClientId"];
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var service = new CommandesService(new ContexteClientWebForms(), new CommandeRepository());
GridCommandes.DataSource = service.CommandesEnCours();
GridCommandes.DataBind();
}
}
Dans cet exemple, la nouvelle application en .NET Core ne lit plus le client dans la session. On le récupère dans l’identité de l’utilisateur connecté, ou dans l’adresse de la page, en vérifiant ses droits.
Le service ne change pas.
La nouvelle application ne peut pas toujours se passer de la session. Elle le peut quand celle-ci ne contient que quelques valeurs simples, qu’on retrouve ailleurs, comme l’identité de l’utilisateur ou l’adresse de la page.
Sinon, il reste les System.Web adapters. Avec la session distante, la nouvelle application lit et écrit la session de l’ancienne, grâce à un point d’accès ajouté à l’ancienne application et protégé par une clé d’API. Les deux applications voient ainsi les mêmes données pendant la cohabitation.
Cela a un coût. Chaque clé de session doit être déclarée avec son type, dans les deux applications, pour être sérialisée (un sérialiseur JSON est fourni). Chaque requête qui utilise la session fait au moins un appel HTTP vers l’ancienne application.
Comment migrer sans tout arrêter ?
Pour une grosse migration, Microsoft recommande de créer une application ASP.NET Core et de la placer devant l’ancienne. Elle sert les routes déjà migrées et transfère les autres au Web Forms via un reverse proxy. Microsoft s’appuie sur son produit YARP, mais d’autres reverse proxies sont possibles. Ce socle, comprenant le proxy et le partage de la session et de la connexion, doit être envisagé comme un projet à part.

Le plus simple est de commencer par migrer une route simple, sans état. On teste le montage, on vérifie que le proxy n’augmente pas trop le temps de réponse.
Quelques critères pour la sélectionner :
- ne demande pas de connexion
- ne lit et n’écrit pas dans la session
- a une logique simple
- ne contient pas de contrôles tiers ni d’
UpdatePanel - est peu visitée
Ces critères se retrouvent souvent dans une page de contact ou d’aide, par exemple. Il faut ensuite tester avec une route qui implémente la connexion et la session afin de compléter le socle.
Pour les bibliothèques, on ne s’occupe que de celles utilisées par les pages en cours de migration, en multi-ciblage. Celles qui utilisent HttpContext.Current suivent le même principe que la session : on le cache derrière une interface, ou à défaut on passe par les System.Web adapters, qui le rendent disponible dans ces bibliothèques.
Au final, rien n’oblige à tout migrer. Il y a par contre un coût : exécuter et maintenir deux applications en parallèle. Cela permet en revanche de repasser une page en Web Forms si sa nouvelle version pose problème.
Quelle technologie cible ?
Microsoft propose un guide pour migrer de Web Forms vers Blazor. Les cibles possibles se classent en trois familles :
- Le rendu serveur, avec Razor Pages ou MVC. La session partagée y fonctionne pendant la cohabitation des deux applications, grâce à la session distante.
- Blazor : tout se fait en C#, mais l’architecture varie selon le mode de rendu. En mode serveur, le code tourne sur le serveur. Chaque clic passe par une connexion permanente, ce qui peut vite mener à des problèmes de performances sur des écrans qui demandent beaucoup d’échanges.
- API côté serveur, et Angular ou React côté client. C’est ce qui demande le plus gros changement de compétences.
Ce choix doit avant tout prendre en compte les compétences de l’équipe en place. Une équipe qui n’a pas de compétence front partira plus sur Razor Pages ou Blazor. À l’inverse, une entreprise avec une équipe faisant déjà de l’Angular ou du React peut faire ce choix sans le regretter.
Dans tous les cas, la logique métier est extraite de la page avant la migration, comme dans l’exemple plus haut. À partir de là, tous les choix cités plus haut pourront en bénéficier via le service. Avec Blazor en mode serveur, la session n’est pas gérée : la nouvelle application doit pouvoir s’en passer. Sinon, il reste Razor Pages ou MVC avec la session distante.
Et si on réécrivait tout ?
Pour chaque page migrée, l’interface est à réécrire. La logique métier, elle, n’est pas réécrite : on la sort de la page, sans System.Web, dans une bibliothèque partagée. Migrer l’ensemble est long et demande une gestion de projet minutieuse.
Le problème de tout migrer d’un bloc, c’est que les évolutions demandées pendant la réécriture devront attendre ou être réalisées deux fois.
Une migration progressive permet au contraire de livrer page par page, de continuer à faire évoluer l’application pendant ce temps, et d’adopter une méthode agile : le projet se découpe plus facilement en lots.
Pages consultées le 15 octobre 2026.