Gestion des valeurs nulles dans ASP.NET Core

Traiter les valeurs NULL est un défi récurrent dans toute application Web moderne. La bonne nouvelle est qu’Asp.net Core est prêt à faire face à ce type de situation. Dans cet article, nous explorerons les outils et les meilleures pratiques qui aident à identifier et à prévenir les problèmes causés par les valeurs nulles.
Les problèmes de valeurs nulles sont courants dans les applications Web qui communiquent entre elles, en échangeant constamment des données. Lorsqu’une valeur attendue n’est pas fournie, des échecs peuvent se produire, tels que des exceptions d’exécution ou un comportement incorrect.
Les valeurs nuls sont l’une des principales causes d’exceptions d’exécution dans les applications Core ASP.NET. Un exemple bien connu parmi les développeurs backend est le redouté NullReferenceException
.
Dans cet article, nous couvrirons certaines fonctionnalités clés disponibles dans ASP.NET Core pour éviter les problèmes courants impliquant des valeurs nulles. Nous explorerons également certaines meilleures pratiques qui aident à sécuriser davantage une application backend, telle que le modèle de conception d’objets NULL.
🕳️ Quelles sont les valeurs nuls?
Dans la programmation générale, les valeurs nulles représentent l’absence d’une valeur. Dans ASP.NET Core, qui utilise le langage C #, NULL est une valeur spéciale où une variable avec une valeur NULL ne pointe à aucun objet ou valeur définie.
Notez un exemple commun d’une variable qui reçoit une valeur nulle:
string address = null;
🤔 Quel est le problème avec les valeurs nuls?
Lorsque vous développez une application Core ASP.NET, vous travaillez avec deux types principaux de données: types de valeur (comme int, bool, datetime) et des types de référence (comme la chaîne, les objets, les listes, etc.).
Le problème avec les valeurs nuls se produit principalement avec les types de référence. Par exemple, imaginez que vous avez un objet client et que vous essayez d’accéder à son nom comme ceci:
var name = customer.Name;
Si l’objet client est nul, cela entraînera une erreur d’exécution appelée NullReferenceException. Cette erreur dit: Vous essayez d’accéder à quelque chose (nom) à l’intérieur d’un objet (client) qui n’existe pas (est nul). C’est comme essayer d’ouvrir un tiroir qui n’est dans aucune armoire; Vous voulez le tiroir, mais l’armoire elle-même n’existe pas.
L’image ci-dessous montre l’exception survenue dans un programme qui vise à capitaliser le nom d’un client, mais depuis le Name
La propriété est nul, une exception est lancée:
🍂 Types de valeur par rapport aux types de référence
Types de valeur
Un type de valeur n’a aucun problème avec les valeurs nulles, car ils ne sont pas nuls par défaut. Contrairement aux types de référence, il stocke directement les données et non une référence (pointeur) vers les données.
Exemples: int, float, double, bool, datetime, struct (coutust) sont stockés sur la pile et contiennent directement la valeur, comme int x = 5
. Dans ce cas, x
stocke la valeur 5, pas une référence.
- Ils ont toujours une valeur définie, même si c’est la valeur par défaut (
int = 0
). - Ils ne peuvent pas être nuls par défaut.
Types de référence
Les types de référence créent une référence (pointeur) vers les données. Dans ce cas, si la valeur de référence est nul et qu’une opération est effectuée dessus, tenter d’y accéder, cela entraînera l’exécution de l’exécution.
Exemples: chaîne, objet, classes.
- Ils sont stockés sur le tas, avec une référence conservée sur la pile.
- Ils peuvent indiquer «rien» – c’est-à-dire qu’ils peuvent être nuls.
🥷 Éviter le problème des propriétés non initialisées avec NULL
Les propriétés non initialisées peuvent provoquer un comportement inattendu, comme le NullReferenceException
. Pour aider à prévenir ce problème et d’autres problèmes de valeurs nulles liées aux propriétés non initialisées, suivez ces solutions:
1. Faites attention aux avertissements
En commençant par .NET 6, les projets de base ASP.NET ont la possibilité d’avertir lorsque les propriétés non initialisées représentent une menace, comme on peut le voir dans l’image ci-dessous:
2. Initialiser les propriétés
Pour résoudre le problème, initialisez simplement les propriétés que les avertissements ont signalés avec des valeurs par défaut, comme dans l’exemple ci-dessous:
public class Customer()
{
public string Name { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public string PhoneNumber { get; set; } = string.Empty;
}
3. Utilisation de types nullables
Une autre option consiste à utiliser les types nullables pour fabriquer les propriétés. Dans ce cas, ajoutez simplement l’opérateur ternaire ?
à la propriété. De plus, il est également possible d’utiliser l’expression Nullable<T>
Pour les types de valeur comme indiqué dans l’exemple ci-dessous:
public class Customer()
{
public string? Name { get; set; }
public Nullable<DateTime> BirthDate { get; set; }
}
4. Initialisation des propriétés dans le constructeur
Une autre façon d’éviter les erreurs de référence nulles consiste à initialiser les valeurs à l’intérieur du constructeur:
public class Customer
{
public Customer()
{
Name = string.Empty;
}
public string Name { get; set; }
}
5. Utilisation du null! Opérateur
L’expression null!
également appelé l’opérateur de favorise nul, peut être utilisé pour indiquer au compilateur que cette propriété se verra plus tard une valeur. Notez l’exemple ci-dessous:
public class Customer
{
public string Name { get; set; } = null!;
}
L’utilisation de l’opérateur de renforcement nul ici signifie que Name
sera attribué correctement plus tard (dans un constructeur, une méthode d’usine, etc.), il ne devrait donc pas lancer des avertissements nullabilité.
Mais soyez prudent! Le null!
L’opérateur attribue toujours Null au moment de l’exécution, ce qui peut provoquer un NullReferenceException
Si vous essayez d’utiliser la propriété avant de l’attribuer correctement.
6. Utilisation du modificateur requis
Le required
L’opérateur de modification est disponible en C # 11 et peut être utilisé pour s’assurer que la propriété est initialisée lors de la création d’une nouvelle instance de la classe, comme démontré dans l’exemple ci-dessous:
var customer = new Customer
{
Name = "John"
};
public class Customer
{
public required string Name { get; set; }
}
💎 Meilleures pratiques: le modèle d’objet nulle
En plus des fonctionnalités disponibles nativement dans ASP.NET Core, il existe certains principes et meilleures pratiques que nous pouvons suivre pour atténuer les risques et les problèmes causés par les valeurs nulles non gérées. L’une des principales initiatives est le modèle de conception connu sous le nom d’objet nul.
L’objet NULL est un modèle de conception qui propose l’utilisation d’un objet nul (représentant «rien»), mais qui est toujours fonctionnel.
Au lieu de retourner null et de le vérifier à chaque point du code, vous renvoyez un objet «à faire» d’une manière sûre et contrôlée. Cet objet nul implémente la même interface que l’objet réel, mais son comportement est neutre ou vide.
Certains avantages de l’utilisation de ce modèle comprennent l’élimination des vérifications nulles, réduisant le risque de NullReferenceException
rendre le code plus propre et avec moins if
S, et suivant le principe du polymorphisme.
Pratiquer le modèle d’objet nul
Pour voir comment un objet NULL est utilisé dans la pratique, nous créerons une API simple qui aura un point de terminaison pour recevoir un message, et si le message n’est pas nul, il devrait le enregistrer. S’il est nul, il ne devrait rien faire. Cependant, la première version montrera comment cela serait fait sans utiliser le modèle d’objet NULL, et la deuxième version utilisera le motif.
Vous pouvez vérifier le code source complet de ce référentiel GitHub: Commandez le code source du journal.
Pour créer l’application, vous pouvez utiliser la commande ci-dessous:
dotnet new web -o OrderLog
❌ sans le motif d’objet nul
Ouvrez l’application et créez un nouveau dossier appelé «Services» et, à l’intérieur, ajoutez la classe suivante:
public class LoggingService
{
public void Log(string message)
{
Console.WriteLine($"[LOG]: {message}");
}
}
Ici, nous venons de créer une classe de service pour afficher un message reçu en tant que paramètre sur la console.
Maintenant dans la classe programme.cs, ajoutez le code suivant:
app.MapPost("https://www.telerik.com/", ([FromServices] LoggingService service, [FromBody] string message) =>
{
if (message != null)
{
service.Log(message);
}
return Results.Ok();
});
Notez que dans cette implémentation du point de terminaison, une vérification nul est effectuée sur le message reçu dans le paramètre, et s’il n’est pas nul, il appelle la méthode qui enregistre le message.
💡 Le problème ici est que lorsque vous travaillez avec des paramètres et des variables avec des valeurs nulles, nous couvrons le risque de provoquer le NullReferenceException
exception. De plus, le code devient sale à mesure que le nombre de validations nulles augmente.
✅ Utilisation du motif d’objet nul
Pour éviter les problèmes avec les valeurs nuls, nous refacterons le code pour implémenter le modèle d’objet NULL.
Pour ce faire, nous créerons deux objets. Le premier à enregistrer le message et le second pour utiliser le cas nul – c’est-à-dire que si le message est nul, il ne fait rien. Les deux objets implémenteront la même interface, mais chacune à sa manière.
Ainsi, dans le dossier des services, ajoutez l’interface suivante:
namespace OrderLog.Services;
public interface ILoggingService
{
void Log(string? message);
}
Notez que nous déclarons uniquement la méthode nécessaire qui liera le message. De plus, nous utilisons l’opérateur ternaire ?
Pour indiquer que le message peut recevoir une valeur nulle.
L’étape suivante consiste à créer les classes. Ajoutez la classe suivante, qui sera la véritable implémentation du journal:
namespace OrderLog.Services;
public class ConsoleLoggingService : ILoggingService
{
public void Log(string? message)
{
Console.WriteLine($"[LOG]: {message}");
}
}
Ajoutez ensuite la classe qui implémentera le scénario nul – c’est-à-dire qu’il ne fera rien.
namespace OrderLog.Services;
public class NullLoggingService : ILoggingService
{
public void Log(string? message)
{
}
}
Maintenant, refactons la classe de programme qui décidera quel scénario exécuter en fonction de la valeur du message. Par conséquent, remplacez le code de classe de programme par ce qui suit:
using Microsoft.AspNetCore.Mvc;
using OrderLog.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<LoggingService>();
builder.Services.AddScoped<NullLoggingService>();
var app = builder.Build();
app.MapPost("https://www.telerik.com/", (
[FromServices] LoggingService realService,
[FromServices] NullLoggingService nullService,
[FromBody] string? message) =>
{
ILoggingService service = message is not null ? realService : nullService;
service.Log(message);
return Results.Ok();
});
app.Run();
💡 Remarquez que nous avons maintenant deux objets de service de journalisation: l’un est le vrai, qui affichera le message de journalisation, tandis que l’autre tiendra compte de la valeur nulle. Ce faisant, nous avons un moyen élégant de gérer les cas nuls, où nous prévoyons des problèmes potentiels et utilisons le modèle d’objet nulle.
Maintenant, nous n’avons plus le if
chèque nul. Nous appelons simplement la classe de service, et tout y est parfaitement résolu.
🔥 exécuter l’application
Exécutons maintenant la demande et faisons deux demandes pour vérifier que les objets réagiront correctement en fonction de la valeur envoyée dans la demande.
Ainsi, d’abord, nous exécutons une demande à l’API, envoyant une valeur à la propriété Message.
Point de terminaison: POSTE – https://localhost:7141
Corps:
"Payment made successfully"
Étant donné que le message ne sera pas nul, le véritable service sera utilisé et le message du journal apparaîtra dans la console:
Maintenant, faites la même demande, mais cette fois sans rien envoyer dans le corps. Cette fois, l’objet NULL sera utilisé, donc rien ne sera enregistré à la console:
✨ Conclusion
J’espère que ce message vous aidera à résoudre les problèmes communs avec les valeurs nulles lors de la création de quelque chose de nouveau dans ASP.NET Core!
Source link