Fermer

avril 18, 2023

Comment migrer votre application WebForms vers Blazor en 6 étapes

Comment migrer votre application WebForms vers Blazor en 6 étapes


Le moment est donc venu de remercier votre application Web Forms pour son service et de lui permettre de profiter d’une retraite paisible, mais comment procédez-vous exactement pour migrer de Web Forms vers Blazor ?

Vous disposez d’une application Web Forms éprouvée qui prend en charge une partie importante de l’entreprise depuis des années. Mais beaucoup de choses ont changé dans le monde du développement Web depuis l’apparition des formulaires Web, et Blazor s’est maintenant imposé comme une alternative stable, performante et productive.

Le moment est venu de remercier votre application Web Forms pour son service et de lui permettre de profiter d’une retraite paisible. Mais par où commencer et quels sont les pièges à éviter en cours de route ?

Voici les étapes clés que vous devrez effectuer pour migrer votre application Web Forms vers Blazor :

  1. Créer un nouveau projet pour la nouvelle interface utilisateur Blazor.
  2. Apportez toutes les références de colis votre application a besoin.
  3. (facultatif) Installez le Pack de compatibilité Windows pour fournir des fonctionnalités Windows uniquement (qui ont été omises dans ASP.NET Core).
  4. Migrez de global.asax vers program.cs.
  5. Soigneusement décochez votre présentation et votre logique métier.
  6. Migrez votre applicationune page ASPX à la fois (ASPX -> composant Blazor).

Explorons chacun :

1. Créez un nouveau projet pour votre interface utilisateur Blazor

La tâche ici consiste à migrer de .NET Framework vers .NET (Core), en particulier Blazor, vous devrez donc commencer par un nouveau projet Blazor. Ce qui signifie que vous devez décider d’utiliser Blazor WASM ou Blazor Server.

À bien des égards, Blazor Server ressemble à une évolution plus naturelle pour une application Web Forms, car tout fonctionne toujours sur le serveur. Si vous souhaitez utiliser Blazor WASM, vous devrez exposer votre logique métier existante via une API Web.

Il vaut la peine de noter .NET 8 semble prêt à bousculer un peu les choses dans ce domaineavec des options pour exécuter les composants Blazor sur le serveur, mais sans s’appuyer sur les connexions socket.

.NET 8 facilitera également l’adoption des composants Blazor pour certaines parties de votre application (vous n’aurez plus besoin d’aller « tout Blazor » juste pour commencer à l’utiliser).

Pour l’instant cependant, tout commence avec ce nouveau projet Blazor.

2. Apporter des packages (dépendances)

Votre application Web Forms repose probablement sur un certain nombre de packages, qui seront répertoriés dans packages.config de votre application. Vous voudrez les migrer vers votre nouveau projet Blazor, mais il se peut que vous ne sachiez pas exactement lesquels vous avez besoin.

Les projets Web Forms répertorient toutes les dépendances sur lesquelles ils s’appuient, tandis que les projets .NET modernes ne répertorient que les dépendances de « niveau supérieur » (et tous les packages/sous-packages associés sont installés automatiquement).

Vous avez quelques options ici. Vous pouvez essayer de faire passer juste le forfaits dont vous savez avoir besoin « dès le départ ». Ou vous préférerez peut-être adopter un « page par page » approche de migration de votre application, auquel cas il peut être préférable de transférer les dépendances au fur et à mesure que vous en avez besoin.

Un facteur clé ici est probablement la taille de votre application. Si vous regardez un mastodonte de mille pages, vous voudrez peut-être élaborer une stratégie dans laquelle vous migrez lentement des parties de l’application existante, en testant soigneusement que tout fonctionne toujours au fur et à mesure.

Une application plus petite peut être mieux migrée en une seule fois.

Vous pouvez ajouter des références de package à votre nouvelle application Blazor dans le fichier .csproj de votre application :

<ItemGroup>
  <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
  <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="7.0.3" />
  <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="7.0.3" />
   ...
</ItemGroup>

De nombreuses dépendances sur lesquelles repose votre application fonctionneront avec .NET (Core). Cela inclut les versions de packages populaires tels que log4net, Entity Framework 6, etc.

Si vous essayez de référencer un package qui n’est pas compatible, vous obtiendrez des erreurs d’exécution lorsque vous lancerez votre nouvelle application (et des erreurs dans Visual Studio).

3. (Facultatif) Installez le pack de compatibilité Windows

.NET est désormais multiplateforme, mais cela signifie que certaines fonctionnalités ont été omises car elles ne fonctionnent que sur Windows.

Si votre application dépend de l’une de ces fonctionnalités « manquantes », vous pouvez installer le pack de compatibilité Windows pour continuer à les utiliser. Cela inclut la prise en charge d’éléments tels que Windows Communication Foundation, Windows EventLog et ODBC (pour n’en nommer que quelques-uns).

Découvrir en savoir plus sur le pack de compatibilité ici.

4. Migrer de global.asax vers program.cs

Votre application WebForm est efficacement amorcée à l’aide de global.asax. C’est là que se déroule une grande partie de la configuration initiale essentielle de votre application.

Dans Blazor, l’équivalent est Program.cs (à partir de .NET 6) ou Program.cs et Startup.cs (version antérieure de .NET).

Voici un exemple de la structure d’une classe Global.asax typique :

public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        
    }   

    protected void Application_Error(object sender, EventArgs e)
    {
        
    }

    protected void Application_End(object sender, EventArgs e)
    {
        
    }
}

.NET (Core) a différents mécanismes que vous pouvez utiliser pour les différentes méthodes ici.

Par exemple, pour exécuter du code au démarrage de votre application, vous pouvez utiliser un service hébergé. Voici un exemple :

namespace Courses.Demos.Server;

public class MyService : IHostedService
{
    private readonly ILogger<MigrateDB> _logger;

    public MyService(ILogger<MigrateDB> logger)
    {
        _logger = logger;
    }
    
    Task IHostedService.StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("App starting");
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("App ending");
        return Task.CompletedTask;
    }
}

Dans Program.cs, nous pouvons enregistrer ce service :

builder.Services.AddHostedService<MyService>();

Avec ça, StartAsync sera exécuté au démarrage de notre application et StopAsync lorsque notre application s’arrête.

5. Décochez soigneusement votre présentation et votre logique métier

Jusqu’à présent, nous nous sommes concentrés sur les mécanismes de migrer votre application, mais vient maintenant la partie amusante (enfin, selon votre définition du plaisir !)

L’un des grands changements de Web Forms à Blazor est que Blazor encourage une séparation beaucoup plus nette des préoccupations.

En général, Les composants Blazor se concentrent sur la partie UI de votre application (comment les choses comme les clics de bouton et d’autres interactions sont gérées). Ils délèguent à un backend (API ou service) l’exécution de la logique métier.

Applications de formulaires Webd’autre part, sont connus pour confondre la présentation et la logique métier.

Voici un exemple partiel d’une page Web Forms aspx :

private List<item> disposedItems;

protected override void Page_Load(object sender, EventArgs e)
{
    SetupServices();
    trans = new Translate(SiteHelper.CurrentCulture);

    if (!IsPostBack)
    {
        ltLogo.Text = Toolbox.SiteUtils.DomainLogo(CurrentUser.Company.DomainID);

        if (!String.IsNullOrEmpty(Request["r"]))
        {
            nRequest request = new nRequest(new Guid(Request["r"]));
            nBarcode barcode = new nBarcode(request.ID, 3);

            if (barcode.ID != Guid.Empty)
            {
                Image1.ImageUrl = "barcodeLabeller.aspx?code=" + barcode.Barcode;
                Literal2.Text = barcode.Barcode;
            }
            else
            {
                Literal2.Text = trans.TranslateString("Barcode Failed to create");
            }

            Literal1.Text += trans.TranslateString("Email") + ": " + request.User.Email + "<br/>";
            Literal1.Text += "<br>" + trans.TranslateString("Customer Ref") + ": " + request.OrderNumber;

            ICollection<DisplayRequestPackage> requestItems = requestService.GetRequestDisplayObjects(request.ID);
            ICollection<DisplayRequestSubPackage> subPackages =
                GetSubPackagesFromRequestItems(requestItems);
            litItems.Text = GetRequestItemsHTML(requestItems);
            if (disposedItems.Count > 0)
            {
                pnlSubPackages.Visible = true;
                rptSubPackages.DataSource = subPackages;
                rptSubPackages.DataBind();
            }
        }
    }
}

Le défi ici vient de la façon dont le code de modification de l’interface utilisateur est mélangé avec le code de logique métier (et/ou d’accès aux données) comme celui-ci :

if (disposedItems.Count > 0)
{
    pnlSubPackages.Visible = true;
    rptSubPackages.DataSource = subPackages;
    rptSubPackages.DataBind();
}

Avec Blazor, nous serions plus susceptibles de récupérer les données à l’avance et de faire réagir l’interface utilisateur à ces données, peut-être même en divisant l’interface utilisateur en plusieurs composants, chacun représentant une petite partie de l’interface utilisateur.

Séparer cela peut sembler une tâche assez ardue, mais nous pouvons la faciliter avec une refactorisation étape par étape avant d’essayer de migrer cela vers Blazor.

Voici quelques tactiques qui peuvent aider à séparer l’interface utilisateur et la logique métier.

Cherchez les coutures

Parfois, votre code Web Forms peut effectuer des appels directs à une base de données (via un référentiel, un magasin ou une autre approche).

D’autres fois, vous constaterez peut-être que vous appelez un service ou une autre forme d ‘«intermédiaire».

Et, parce que la vie est désordonnée, vous trouverez parfois vos pages aspx appelant une combinaison des deux (et de nombreux autres appels en plus !).

Prenons ce projet de formulaires Web « hérité » représentatif :

schéma montrant divers composants d'une application Web et comment ils sont connectés.  Un certain nombre de cases représentant les composants d'une application Web.  Les composants sont reliés par des flèches pour indiquer quels composants appellent quels autres composants.  Les composants de l'interface utilisateur sont en haut et le reste sont divers services, assistants et référentiels

Cette page aspx rassemble des données provenant de diverses sources, y compris à la fois un Helpdesk Service et un niveau inférieur User Repository.

Il est beaucoup plus facile de migrer vers une nouvelle pile d’interface utilisateur si nous pouvons utiliser ou créer des coutures claires dans cette architecture.

Idéalement, nous voulons une limite claire qui expose les méthodes pour interagir avec le backend (pour interroger les données, mais aussi pour les faire muter, tout en s’assurant que les règles métier importantes sont respectées).

diagramme montrant divers composants d'une application Web avec une limite claire autour de la logique métier.  un certain nombre de cases, représentant les composants d'une application Web.  Les composants relatifs à la logique métier sont entourés d'un encadré vert

Si vous l’avez déjà, vous pouvez continuer et appeler ceux de votre application Blazor, soit directement (Serveur Blazor) ou en exposant ces appels via une API (Blazor WASM).

Voici, par exemple, un composant Blazor qui appelle le HelpdeskService dans l’exemple ci-dessus :

@inject IHelpdeskService HelpdeskService

<ul>
    @foreach(var ticket in tickets){
    	<li>@ticket.Subject</li>    
    }
</ul>
@code {
    
    IEnumerable<Ticket> tickets;
    
 	protected override void OnInitialized() {
        tickets = HelpdeskService.ListForUser("someUserId");
    }
    
}

Mais si la page aspx existante effectue plusieurs appels, pour assembler des données à partir de divers endroits, cela pourrait en fait rendre les choses beaucoup plus faciles de créer une nouvelle couture, une nouvelle méthode qui extrait de plusieurs sources et renvoie uniquement les données nécessaires pour le spécifique page.

public interface ITicketListPageQuery {    
    TicketListResponse Get(string userId);    
}

public record TicketListResponse {
    public int UserTicketCount { get; set; }
    public IEnumerable<TicketListItem> Tickets { get; set; }
}

public record TicketListItem {
    public int Id { get; set; }
    public string Title { get; set; }
    public DateTime LastModified { get; set; }
}

Dans cet exemple, l’implémentation peut appeler plusieurs objets de niveau inférieur pour extraire les données dont elle a besoin pour remplir le TicketListResponse.

Vous pouvez effectuer cette refactorisation et utiliser le ITicketListPageQuery avec le code Web Forms existant dans un premier temps.

Cette refactorisation « en place » peut ressembler à un mouvement latéral ou même en arrière mais, en pratique, préparer le terrain comme celui-ci (tout en « gardant les lumières allumées » dans l’application Web Forms existante) rend généralement la migration Blazor beaucoup plus facile, et beaucoup moins risqué, car vous savez que les appels backend existants sont fiables.

Pousser la logique vers le bas dans les objets du domaine

Voici un autre exemple de page aspx :

public class Default 
{
    ...

    private void GetUserSummaryForTickets(IEnumerable<Ticket> orderedTickets)
    {
        foreach (var ticket in orderedTickets)
        {
            ticket.User = _helpdeskService.User.ById(ticket.UserId);

            if (ticket.DateCreated > new DateTime(2018, 1, 1))
            {
                ticket.Text = ticket.Text + "Legacy - ";
            }
        }
    }  
}

public class Ticket
{
    public DateTime DateCreated { get; internal set; }
    public string Text { get; set; }
    
    public int UserId { get; set; }
    public User User { get; set; }
    public Guid Id { get; set; }
}

Remarquez comment Ticket voici une ancienne classe C # simple, avec des propriétés et sans logique métier.

Dans le code de la Default page aspx nous effectuons une if vérifier les valeurs de Ticket.

if (ticket.DateCreated > new DateTime(2018, 1, 1))
{
    ticket.Text = ticket.Text + "Legacy - ";
}

Une amélioration ici consisterait à enfoncer cette logique dans le Ticket objet de domaine.

public class Default 
{
    ...

    private void GetUserSummaryForTickets(IEnumerable<Ticket> orderedTickets)
    {
        foreach (var ticket in orderedTickets)
        {
            ticket.User = _helpdeskService.User.ById(ticket.UserId);

            if (ticket.IsLegacy())
            {
                ticket.Text = ticket.Text + "Legacy - ";
            }
        }
    }  
}

public class Ticket
{
    public DateTime DateCreated { get; internal set; }
    public string Text { get; set; }
    
    public int UserId { get; set; }
    public User User { get; set; }
    public Guid Id { get; set; }

    public bool IsLegacy()
    {
        return DateCreated > new DateTime(2018, 1, 1);
    }
}

Cela encapsule parfaitement une logique commerciale clé (est un ticket « Legacy ») et dissocie la page aspx des détails de mise en œuvre de la façon dont cela est décidé.

Migrez votre application, une page ASPX à la fois (composant ASPX vers Blazor)

La bonne nouvelle est qu’une fois que vous avez séparé la logique métier et la logique de présentation, vous êtes prêt à commencer la migration de vos pages.

En supposant que vous avez réussi à créer une frontière claire entre votre interface utilisateur et votre logique métier, vous pouvez maintenant pointer votre interface utilisateur Blazor vers le service/requête pertinent et c’est parti.

@inject ITicketListPageQuery TicketListQuery

<ul>
    @foreach(var ticket in model.Tickets){
    	<li>@ticket.Subject</li>    
    }
</ul>
@code {
    
    TicketListResponse model;
    
    protected override void OnInitialized() {
        tickets = TicketListQuery.Get("someUserId");
    }
    
}

Blazor s’appuie fortement sur l’injection de dépendances – vous pouvez injecter des dépendances dans votre composant Blazor avec cette syntaxe :

@inject ITicketListPageQuery TicketListQuery 

Ensuite, utilisez-les dans votre code :

TicketListQuery.Get();

Pour que cela fonctionne, vos services devront être enregistrés dans le conteneur DI. La façon la plus simple de le faire est de Program.cs.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<ITicketListPageQuery, TicketListPageQuery>();

De Page_Load à OnInitialized

Si vous avez du code dans le Page_Load pour vos pages aspx, vous voudrez l’exécuter dans OnInitialized (ou son équivalent asynchrone) dans votre application Blazor.

@code {
	protected override void OnInitialized() {
        tickets = TicketListQuery.Get("someUserId");
    }
}

Utiliser DataAnnotations pour gérer la validation

Si vous avez utilisé la validation dans vos pages aspx, vous pouvez implémenter la même validation à l’aide de DataAnnotations dans votre interface utilisateur Blazor.

Voici, par exemple, un formulaire pour éditer un ticket dans notre exemple de helpdesk.

Formulaires Web

<div>
    <label>Subject</label>
    <div>
        <asp:TextBox ID="Subject" runat="server" CssClass="form-control"></asp:TextBox>
        <asp:RequiredFieldValidator runat="server" ControlToValidate="Subject" ErrorMessage="Ticket Subject is required." />
    </div>
</div>

Blazor

<EditForm Model="ticket" OnValidSubmit="@...">
    <DataAnnotationsValidator />

    <div>
        <label>Subject</label>     
        <div>            
         	<InputText class="form-control" @bind-Value="ticket.Subject" />
            <ValidationMessage For="(() => ticket.Subject)" />       
        </div>          
    </div>

    ...
</EditForm>

Voici ça Ticket classe (appelée ticket au-dessus de):

using System.ComponentModel.DataAnnotations;

public class Ticket
{
    [Required]
    public string? Subject { get; set; }
}

En résumé

En fonction de la séparation entre l’interface utilisateur et la logique métier dans votre application Web Forms existante, vous devrez peut-être effectuer une petite refactorisation avant de pouvoir commencer à utiliser Blazor.

Si tel est le cas, effectuez ces refactorisations « in situ », en mettant à jour les pages aspx des formulaires Web pour utiliser votre code nouvellement refactorisé.

Lorsque vous avez exposé des coutures claires pour une ou plusieurs parties de votre application, vous pouvez commencer à consommer celles de vos nouveaux composants Blazor brillants.

La plupart des éléments de votre application Web Forms peuvent être migrés vers .NET (Core), y compris le code de global.asax, les dépendances et la logique de validation.

Enfin, .NET 8 semble prêt à rendre tout cela un peu plus facile, avec la possibilité d’adopter lentement Blazor pour certaines parties de votre application (plutôt que pour l’ensemble), mais vous devrez toujours séparer vos problèmes d’interface utilisateur et de logique métier. , donc le temps passé à refactoriser est du temps bien dépensé !


Essayez Telerik aujourd’hui

Développez de nouvelles applications Blazor et modernisez les projets Web hérités en deux fois moins de temps grâce à une grille hautes performances et à plus de 100 composants Blazor véritablement natifs et faciles à personnaliser pour répondre à toutes les exigences. Essayez Progression Interface utilisateur Telerik pour Blazor gratuitement avec notre essai de 30 jours et profitez de notre assistance de pointe.

Essayez l’interface utilisateur Telerik pour Blazor

Ou commencez avec un Progress Essai Telerik DevCraft aujourd’hui! Le DevCraft suite est la collection la plus puissante d’outils de développement JavaScript Telerik .NET et Kendo UI. Il comprend des composants d’interface utilisateur modernes, riches en fonctionnalités et conçus par des professionnels pour les applications Web, de bureau et mobiles ; solutions intégrées de reporting et de gestion de rapports ; bibliothèques de traitement de documents; et des outils de test et de simulation automatisés.

Essayez Telerik DevCraft




Source link