Retour aux articles

De 127 warnings à zéro : ce que les avertissements de mon projet .NET cachaient

De 127 warnings à zéro : ce que les avertissements de mon projet .NET cachaient

Vous connaissez cette ligne, en bas de la sortie de dotnet build ?

La génération a réussi.
    127 Avertissement(s)
    0 Erreur(s)

Pendant des mois, je l'ai lue comme « ça compile, tout va bien ». Les warnings, c'était du bruit : des histoires de null théoriques, des bibliothèques un peu pointilleuses. Rien d'urgent.

Un jour, j'ai décidé de les corriger, un par un. Je m'attendais à une corvée. J'ai trouvé de vrais bugs, dont certains en production depuis longtemps, sans qu'aucune erreur ne s'affiche jamais.

TL;DR

  • Plus de la moitié de mes warnings venaient de la nullabilité (CS8618, CS8602...). La plupart étaient des faux problèmes... mais pas tous.
  • Les warnings de l'analyseur MudBlazor pointaient des attributs supprimés de la bibliothèque : ignorés en silence, ils cassaient des fonctionnalités.
  • Une balise Razor inconnue (RZ10012) cachait une boîte de dialogue mal construite.
  • Aujourd'hui, la CI compile avec -warnaserror : un nouveau warning fait échouer le build.

Le grand tri

En triant les 127 warnings par type, trois familles sont apparues :

  1. La nullabilité : de loin la plus nombreuse (CS8618, CS8602, CS8601, CS8604...).
  2. Les analyseurs : MudBlazor (MUD0002) et Blazor (BL0008, RZ10012).
  3. Le reste : une méthode obsolète, des champs jamais utilisés (du code mort).

J'ai commencé par le plus nombreux. Et c'est là que j'ai eu ma première surprise.

Nullabilité : 90 % de bruit, 10 % de vrais bugs

Une bonne partie des warnings venait de petites approximations sans conséquence. Par exemple, des méthodes de conversion déclarées comme pouvant renvoyer null... alors qu'elles ne le font jamais :

// Avant : le « ? » est faux, la méthode renvoie toujours un objet
public static BlogCategoryDto? ToDto(this BlogCategory entity, string language)

// Après : le type dit la vérité, et les warnings des appelants disparaissent
public static BlogCategoryDto ToDto(this BlogCategory entity, string language)

Ou les services injectés dans les composants Blazor, que le compilateur ne voit pas initialisés :

[Inject]
private IBlogService BlogService { get; set; } = default!;

Le = default! dit au compilateur : « je sais, c'est renseigné par l'injection de dépendances ». Rien de grave, mais une fois ce bruit retiré, les vrais problèmes sont devenus visibles.

Comme celui-ci, dans la conversion du CV :

var translation = experience.Translations.FirstOrDefault(t => t.LanguageCode == language);

return new ExperienceDto
{
    Position = translation?.Position,   // prudent...
    Description = translation.Description // ...mais pas ici !
};

Le développeur (moi) avait mis un ?. sur une ligne, et oublié la suivante. Tant que chaque expérience était traduite, tout allait bien. Mais il aurait suffi d'une expérience sans traduction anglaise pour faire planter la page du CV en anglais. Le warning CS8602 le disait depuis le début.

Même chose pour l'envoi d'e-mails : si un paramètre SMTP manquait en base, le code passait null à la bibliothèque d'envoi, qui levait une exception peu parlante. Maintenant, le cas est géré, avec un message clair dans les logs.

MudBlazor : les attributs fantômes

C'est la partie qui m'a le plus surpris. L'analyseur MudBlazor signalait ceci :

MUD0002: Illegal Attribute 'IsVisible' on 'MudDialog'.
'IsVisible' was removed in v7 and replaced by 'Visible'.

Au fil des mises à jour de MudBlazor, des paramètres ont été renommés ou supprimés. Mais Blazor ne lève aucune erreur pour un attribut inconnu : il l'ignore, tout simplement. Concrètement, dans l'administration de mon site :

  • la boîte de confirmation pour supprimer une catégorie ne s'ouvrait plus (IsVisible → Visible) ;
  • le logo des entreprises dans la liste des offres d'emploi ne s'affichait pas (Image sur MudAvatar n'existe plus) ;
  • la marge des onglets de la fenêtre d'édition d'une offre avait disparu (PanelClass → TabPanelsClass).

Trois fonctionnalités cassées, aucune erreur, aucune trace. Juste un warning, perdu au milieu de 126 autres.

@* Avant : attribut supprimé, ignoré en silence *@
<MudDialog @bind-IsVisible="showDeleteDialog">

@* Après *@
<MudDialog @bind-Visible="showDeleteDialog">

La balise qui n'existait pas

Dernier exemple, avec un warning Razor :

RZ10012: Found markup element with unexpected name 'MudDialogActions'.

Dans la fenêtre d'insertion d'image de mon éditeur Markdown, j'avais écrit <MudDialogActions>. Ce composant n'existe pas. Razor l'a donc traité comme une balise HTML inconnue : les boutons s'affichaient quand même, mais en vrac, en dehors de la structure prévue par MudBlazor. La bonne structure :

<MudDialog>
    <DialogContent>
        ...
    </DialogContent>
    <DialogActions>
        <MudButton OnClick="Cancel">Annuler</MudButton>
        <MudButton Color="Color.Primary" OnClick="Submit">Insérer</MudButton>
    </DialogActions>
</MudDialog>

Ne plus jamais revenir à 127

Corriger, c'est bien. Ne pas recommencer, c'est mieux. Dans la CI (GitHub Actions), le build des branches et des pull requests utilise maintenant -warnaserror :

- name: Build
  run: dotnet build src/MonProjet.slnx --configuration Release --no-restore -warnaserror

Un nouveau warning, et la CI échoue. Y compris après une mise à jour automatique des dépendances : si une nouvelle version de MudBlazor supprime un attribut, je le saurai avant de déployer, pas trois mois après en cliquant sur un bouton qui ne fait rien.

J'ai volontairement laissé le déploiement sans cette option : je ne veux pas qu'un warning m'empêche de corriger un bug urgent en production.

Ce que je retiens

  • Un warning ignoré, c'est un bug qu'on n'a pas encore trouvé. Pas toujours, mais assez souvent pour que ça vaille le coup.
  • Le bruit cache le signal. Avec 127 warnings, impossible de voir celui qui compte. À zéro, le moindre nouveau saute aux yeux.
  • Les analyseurs des bibliothèques sont précieux. Celui de MudBlazor m'a signalé exactement ce que les mises à jour avaient cassé.
  • Il faut verrouiller. Sans -warnaserror, je serais revenu à 127 en quelques mois.

Ça m'a pris une soirée. Ça m'a rendu trois fonctionnalités et évité au moins un plantage en production. Et vous, combien de warnings dans votre build ?

Commentaires (0)

Aucun commentaire pour le moment. Soyez le premier à commenter !

Laisser un commentaire

Votre e-mail ne sera pas publié.
An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please reload the page.