Structure de projet pour les applications Blazor

Conseil

Ce contenu est un extrait du livre électronique, Blazor pour les développeurs ASP NET Web Forms pour Azure, disponible dans la documentation .NET ou au format PDF à télécharger gratuitement pour le lire hors connexion.

Blazor-for-ASP-NET-Web-Forms-Developers eBook cover thumbnail.

Malgré leurs différences importantes au niveau de la structure de projet, ASP.NET Web Forms et Blazor partagent de nombreux concepts similaires. Ici, nous allons examiner la structure d’un projet Blazor et le comparer à un projet ASP.NET Web Forms.

Pour créer votre première application Blazor, suivez les instructions des étapes de démarrage de Blazor. Vous pouvez suivre les instructions pour créer une application Blazor Server ou une application BlazorWebAssembly hébergée dans ASP.NET Core. À l’exception de la logique spécifique au modèle d’hébergement, la plupart du code dans les deux projets est identique.

Fichier projet

Les applications Blazor Server sont des projets .NET. Le fichier projet de l’application Blazor Server est d’une simplicité à toute épreuve :

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

</Project>

Le fichier projet d’une application BlazorWebAssembly semble légèrement plus complexe (les numéros exacts des version peuvent varier) :

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" PrivateAssets="all" />
  </ItemGroup>

</Project>

Le projet BlazorWebAssembly cible Microsoft.NET.Sdk.BlazorWebAssembly au lieu du SDK Microsoft.NET.Sdk.Web parce qu’il s’exécute dans le navigateur sur un runtime .NET basé sur WebAssembly. Vous ne pouvez pas installer .NET dans un navigateur web comme vous le pouvez sur un serveur ou un ordinateur de développement. Par conséquent, le projet référence le framework Blazor avec des références de package individuelles.

En comparaison, un projet ASP.NET Web Forms par défaut compte près de 300 lignes de code XML dans son fichier .csproj, dont la plupart liste explicitement les différents fichiers de code et de contenu dans le projet. Depuis la publication de .NET 5, les applications Blazor Server et BlazorWebAssembly peuvent facilement partager un runtime unifié.

Bien qu’elles soient prises en charge, les références d’assembly individuelles sont moins courantes dans les projets .NET. La plupart des dépendances de projet sont gérées comme des références de package NuGet. Vous devez uniquement référencer les dépendances de package de niveau supérieur dans les projets .NET. Les dépendances transitives sont incluses automatiquement. Au lieu d’utiliser le fichier packages.config que l’on trouve couramment dans les projets ASP.NET Web Forms pour référencer les packages, les références de package sont ajoutées au fichier projet à l’aide de l’élément <PackageReference>.

<ItemGroup>
  <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>

Point d’entrée

Le point d’entrée de l’application Blazor Server est défini dans le fichier Program.cs, comme vous le verriez dans une application console. Lorsque l’application s’exécute, elle crée et exécute une instance hôte web en utilisant les valeurs par défaut propres aux applications web. L’hôte web gère le cycle de vie de l’application Blazor Server et configure les services au niveau de l’hôte. Parmi ces services, citons par exemple la configuration, la journalisation, l’injection de dépendances et le serveur HTTP. Ce code est en grande partie réutilisable et reste souvent inchangé.

using BlazorApp3.Areas.Identity;
using BlazorApp3.Data;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
builder.Services.AddSingleton<WeatherForecastService>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

Les applications BlazorWebAssembly définissent également un point d’entrée dans Program.cs. Le code semble légèrement différent. Le code est similaire en ce sens qu’il configure l’hôte d’application pour fournir les mêmes services de niveau hôte à l’application. Toutefois, l’hôte d’application WebAssembly ne configure pas de serveur HTTP parce qu’il s’exécute directement dans le navigateur.

Les applications Blazor n’utilisent pas de fichier Global.asax pour définir la logique de démarrage de l’application. À la place, cette logique est contenue dans Program.cs ou dans une classe Startup associée qui est référencée dans Program.cs. Dans les deux cas, ce code est utilisé pour configurer l’application et tous les services spécifiques à l’application.

Dans une application Blazor Server, le fichier Program.cs montré est utilisé pour configurer le point de terminaison pour la connexion en temps réel utilisée par Blazor entre les navigateurs clients et le serveur.

Dans une application BlazorWebAssembly, le fichier Program.cs définit les composants racines de l’application et où ils doivent être rendus :

using BlazorApp1;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

await builder.Build().RunAsync();

Fichiers statiques

Contrairement aux projets ASP.NET Web Forms, les fichiers d’un projet Blazor ne peuvent pas tous être demandés en tant que fichiers statiques. Seuls les fichiers du dossier wwwroot sont adressables sur le web. Ce dossier est appelé « racine web » de l’application. Tout ce qui se trouve en dehors de la racine web de l’application n’est pas adressable sur le web. Cette configuration fournit un niveau de sécurité supplémentaire qui empêche l’exposition accidentelle des fichiers projet sur le web.

Configuration

La configuration dans les applications ASP.NET Web Forms est généralement gérée à l’aide d’un ou plusieurs fichiers web.config. Les applications Blazor n’ont généralement pas de fichiers web.config. Si c’est le cas, le fichier est utilisé uniquement pour configurer les paramètres spécifiques à IIS lorsqu’ils sont hébergés sur IIS. De leur côté, les applications Blazor Server utilisent les abstractions de configuration ASP.NET Core. (Actuellement, les applications BlazorWebAssembly ne prennent pas en charge les mêmes abstractions de configuration, mais ce sera peut-être une fonctionnalité qui sera ajoutée plus tard.) Par exemple, l’application Blazor Server par défaut stocke certains paramètres dans appsettings.json.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Vous en apprendrez plus sur la configuration dans les projets ASP.NET Core dans la section Configuration.

Composants Razor

La plupart des fichiers des projets Blazor sont des fichiers .razor. Razor est un langage de création de modèles basé sur HTML et C# qui est utilisé pour générer dynamiquement l’interface utilisateur web. Les fichiers .razor définissent les composants qui constituent l’interface utilisateur de l’application. Les composants sont en grande partie identiques pour les applications Blazor Server et BlazorWebAssembly. Les composants dans Blazor sont analogues aux contrôles utilisateur dans ASP.NET Web Forms.

Chaque fichier de composant Razor est compilé dans une classe .NET lors de la génération du projet. La classe générée capture l’état, la logique de rendu, les méthodes de cycle de vie, les gestionnaires d’événements et autres logiques du composant. Vous en apprendrez plus sur la création de composants dans la section Création de composants d’interface utilisateur réutilisables avec Blazor.

Les fichiers _Imports.razor ne sont pas des fichiers de composants Razor. En fait, ils définissent un ensemble de directives Razor à importer dans les autres fichiers .razor dans le même dossier et dans ses sous-dossiers. Par exemple, un fichier _Imports.razor est un moyen conventionnel d’ajouter des directives using pour les espaces de noms couramment utilisés :

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using BlazorApp1
@using BlazorApp1.Shared

Pages

Où sont les pages dans les applications Blazor ? Blazor ne définit pas d’extension de fichier distincte pour les pages adressables, comme les fichiers .aspx dans les applications ASP.NET Web Forms. En fait, les pages sont définies en affectant des routes aux composants. Une route est généralement attribuée en utilisant la directive Razor @page. Par exemple, le composant Counter créé dans le fichier Pages/Counter.razor définit la route suivante :

@page "/counter"

Le routage dans Blazor est géré côté client, et non sur le serveur. Lorsque l’utilisateur circule dans le navigateur, Blazor intercepte la navigation, puis rend le composant avec la route correspondante.

Actuellement, les routes de composants ne sont pas déduites par l’emplacement du fichier du composant, comme elles le sont avec les pages .aspx ou ASP.NET Core Razor Pages. Cette fonctionnalité sera peut-être ajoutée plus tard. Chaque route doit être spécifiée explicitement sur le composant. Le stockage des composants routables dans un dossier Pages n’a pas de signification particulière, c’est par pure convention.

Vous en apprendrez plus sur le routage dans Blazor dans la section Pages, routage et mises en page.

Layout

Dans les applications ASP.NET Web Forms, une mise en page commune est gérée à l’aide de pages maîtres (Site.Master). Dans les applications Blazor, la mise en page est gérée avec des composants de mise en page (Shared/MainLayout.razor). Les composants de mise en page sont abordés plus en détail dans la section Page, routage et mises en page.

Amorcer Blazor

Pour amorcer Blazor, l’application doit :

  • Spécifier où, dans la page, le composant racine (App.Razor) doit être rendu.
  • Ajouter le script du framework Blazor correspondant.

Dans l’application Blazor Server, la page hôte du composant racine est définie dans le fichier _Host.cshtml. Ce fichier définit une page Razor, pas un composant. Les pages Razor utilisent la syntaxe Razor pour définir une page adressable au serveur, très similaire à une page .aspx.

@page "/"
@namespace BlazorApp3.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    Layout = "_Layout";
}

<component type="typeof(App)" render-mode="ServerPrerendered" />

L’attribut render-mode est utilisé pour définir où un composant de niveau racine doit être rendu. L’option RenderMode indique la manière dont le composant doit être rendu. Le tableau suivant présente les options RenderMode prises en charge.

Option Description
RenderMode.Server Rendue de manière interactive une fois qu’une connexion au navigateur est établie
RenderMode.ServerPrerendered D’abord pré-rendue, puis rendue de manière interactive
RenderMode.Static Rendue en tant que contenu statique

Le fichier _Layout.cshtml contient le code HTML par défaut de l’application et de ses composants.

@using Microsoft.AspNetCore.Components.Web
@namespace BlazorApp3.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
    <link href="BlazorApp3.styles.css" rel="stylesheet" />
    <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
    @RenderBody()

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>

    <script src="_framework/blazor.server.js"></script>
</body>
</html>

La référence de script à _framework/blazor.server.js établit la connexion en temps réel au serveur, puis traite toutes les interactions utilisateur et les mises à jour de l’interface utilisateur.

Dans l’application BlazorWebAssembly, la page hôte est un fichier HTML statique simple sous wwwroot/index.html. L’élément <div> avec l’ID appelé app est utilisé pour indiquer où le composant racine doit être rendu.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>BlazorApp1</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="BlazorApp1.styles.css" rel="stylesheet" />
</head>

<body>
    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

Le composant racine à rendre est spécifié dans le fichier Program.cs de l’application avec la flexibilité nécessaire pour inscrire les services via l’injection de dépendances. Pour plus d’informations, consultez Injection de dépendances Blazor ASP.NET Core.

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

Sortie de la génération

Lorsqu’un projet Blazor est généré, tous les fichiers de composant et de code Razor sont compilés dans un seul assembly. Contrairement aux projets ASP.NET Web Forms, Blazor ne prend pas en charge la compilation du runtime de la logique d’interface utilisateur.

Exécuter l’application avec le Rechargement à chaud

Pour exécuter l’application Blazor Server, appuyez sur F5 dans Visual Studio pour qu’elle s’exécute avec le débogueur attaché, ou Ctrl + F5 pour qu’elle s’exécute sans le débogueur attaché.

Pour exécuter l’application BlazorWebAssembly, choisissez l’une des approches suivantes :

  • Exécuter le projet client directement à l’aide du serveur de développement.
  • Exécuter le projet serveur lors de l’hébergement de l’application avec ASP.NET Core.

Les applications BlazorWebAssembly peuvent être déboguées à la fois dans le navigateur et dans Visual Studio. Pour plus de détails, consultez Déboguer ASP.NET Core BlazorWebAssembly.

Les applications Blazor Server et BlazorWebAssembly prennent en charge le Rechargement à chaud dans Visual Studio. Le Rechargement à chaud est une fonctionnalité qui met automatiquement à jour les modifications apportées à une application Blazor en direct, dans le navigateur. Vous pouvez désactiver le Rechargement à chaud s’il est activé à partir de son icône dans la barre d’outils :

Visual Studio 2022: Hot Reload menu item and icon.

La sélection de l’accent circonflexe à côté de l’icône révèle des options supplémentaires. Vous pouvez activer ou désactiver le Rechargement à chaud, redémarrer l’application et choisir si le Rechargement à chaud doit ou non se produire chaque fois qu’un fichier est enregistré.

Visual Studio 2022: Hot Reload menu item with expanded options.

Vous pouvez également accéder à des options de configuration supplémentaires. La boîte de dialogue de configuration vous permet de spécifier si le Rechargement à chaud doit être activé lors du débogage (avec Modifier et continuer), lors d’un démarrage sans débogage ou lors de l’enregistrement d’un fichier.

Visual Studio 2022: Hot Reload configuration options from the

La « boucle interne du développeur » a été considérablement simplifiée avec le Rechargement à chaud. Sans le Rechargement à chaud, un développeur Blazor devrait normalement redémarrer et réexécuter l’application après chaque modification, en accédant à la partie appropriée de l’application. Avec le Rechargement à chaud, les modifications peuvent être apportées à l’application en cours d’exécution sans avoir à redémarrer dans la plupart des cas. Le Rechargement à chaud conserve même l’état des pages, donc il n’est pas nécessaire de réentrer les valeurs de formulaire ou de récupérer l’application là où vous en avez besoin.