Fazeo Software Réserver 45 min (s’ouvre dans un nouvel onglet)
Menu
Tous les billets

Par Léo Fazendeiro. 8 min de lecture.

Les Web Forms en 2026 : la modernisation par étapes

Mon application Web Forms est en 4.8. Peut-elle rester comme ça ou dois-je la migrer ?

Couverture du billet : Web Forms en 2026, qu’en faire ? Architecture et modernisation .NET. Un développeur, pensif devant l’écran d’une application Web Forms (pages .aspx, code-behind, contrôles serveur, logique métier, accès aux données), reliée à des services externes, une base SQL existante et d’autres applications. Quatre pistes sont posées en questions : tout réécrire, ne rien toucher, extraire d’abord, page par page. Décision à prendre.

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.

Schéma de la migration progressive vers ASP.NET Core. Les utilisateurs envoient leurs requêtes HTTP à l’application ASP.NET Core. Elle sert elle-même les routes migrées, comme /contact, la première à migrer, et transmet les autres routes, via un proxy, à l’application Web Forms. Les deux applications tournent en parallèle et partagent la session.

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 :

  1. 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.
  2. 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.
  3. 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.

Un regard extérieur sur votre parc ?

Je vous accompagne de l’état des lieux à la modernisation par lots, au forfait : un format, un prix et une date de démarrage possible, annoncés avant de commencer.