La personnalisation des contrats JSON et l'injection de dépendances sont des concepts clés pour le développement d'applications robustes et maintenables en C#. Cet article explore ces concepts en détail, en mettant l'accent sur leur application pratique et leurs avantages.
Personnalisation des contrats JSON avec System.Text.Json
La bibliothèque System.Text.Json en C# construit un contrat JSON pour chaque type .NET, définissant la manière dont le type doit être sérialisé et désérialisé. Ce contrat est dérivé de la forme du type, incluant ses propriétés, ses champs et son implémentation des interfaces IEnumerable ou IDictionary.
Introduction à la personnalisation des contrats JSON
À partir de .NET 7, il est possible de personnaliser ces contrats JSON pour mieux contrôler la conversion des types en JSON et inversement. Cette personnalisation offre une flexibilité accrue pour adapter la sérialisation et la désérialisation aux besoins spécifiques d'une application.
Méthodes de personnalisation
Il existe deux principales façons de personnaliser les contrats JSON :
- Modificateurs : Un modificateur est une
Action<JsonTypeInfo>ou une méthode avec un paramètreJsonTypeInfoqui obtient l'état actuel du contrat et y apporte des modifications. Par exemple, il est possible d'itérer dans les propriétés préremplies sur leJsonTypeInfospécifié pour trouver celle qui vous intéresse, puis modifier sa propriétéJsonPropertyInfo.Get(pour la sérialisation) ouJsonPropertyInfo.Set(pour la désérialisation). - Résolveurs personnalisés : Vous pouvez créer un résolveur personnalisé qui implémente la logique de personnalisation souhaitée. Il est également possible de combiner un résolveur personnalisé avec d'autres, comme le résolveur par défaut.
Utilisation de JsonTypeInfo.Kind
La propriété JsonTypeInfo.Kind indique comment le convertisseur sérialise un type donné, par exemple en tant qu'objet ou en tant que tableau, et si ses propriétés sont sérialisées. Cette propriété peut être interrogée pour déterminer les aspects du contrat JSON d'un type que vous pouvez configurer.
Lire aussi: Droit Contractuel et Force Majeure
Object: Le convertisseur sérialise le type dans un objet JSON et utilise ses propriétés.Array: Le convertisseur sérialise le type dans un tableau JSON.None: Le convertisseur ne spécifie pas comment il sérialise le type ni les propriétésJsonTypeInfoqu'il utilisera.
Exemples de personnalisation
Voici quelques exemples de personnalisation des contrats JSON :
- Incrémentation de la valeur d'une propriété lors de la désérialisation : Un modificateur peut être utilisé pour incrémenter la valeur d'une propriété lors de la désérialisation en modifiant son délégué
JsonPropertyInfo.Set. Un attribut personnalisé peut être introduit pour localiser la propriété dont la valeur doit être incrémentée. - Inclusion des champs privés : Par défaut,
System.Text.Jsonignore les propriétés et les champs privés. Un attribut à l'échelle de la classe, tel queJsonIncludePrivateFieldsAttribute, peut être ajouté pour modifier cette valeur par défaut. - Filtrage des propriétés par type : Il est possible de filtrer des propriétés avec un type spécifique que vous ne souhaitez pas exposer aux utilisateurs. Une méthode d'extension
IList<T>peut être utilisée pour supprimer de la listeJsonTypeInfo.Propertiestoutes les propriétés qui ont le type spécifié. - Gestion des guillemets autour des valeurs numériques : Si le JSON d'entrée contient des guillemets autour de certains types numériques, mais pas pour d'autres, il est possible de modifier le comportement pour toutes les valeurs
int. Avant .NET 7, il était nécessaire d'écrire un convertisseur personnalisé pour corriger ce comportement.
Avantages de la personnalisation des contrats JSON
La personnalisation des contrats JSON offre plusieurs avantages :
- Flexibilité : Permet d'adapter la sérialisation et la désérialisation aux besoins spécifiques d'une application.
- Contrôle : Offre un contrôle précis sur la manière dont les types sont convertis en JSON et inversement.
- Réduction du code : Évite d'écrire des convertisseurs personnalisés pour des cas simples.
- Amélioration de la lisibilité : Permet de rendre le code plus clair et plus facile à comprendre.
Injection de dépendances
L'injection de dépendances (ID) est un modèle de conception qui permet de réduire le couplage entre les classes et d'améliorer la testabilité et la maintenabilité du code.
Principes de l'injection de dépendances
L'injection de dépendances repose sur les principes suivants :
- Inversion de contrôle (IoC) : Un programme qui respecte les principes de l'inversion de contrôle n'est plus totalement maître des éléments nécessaires à son fonctionnement, mais se place plutôt comme une brique faisant partie d'un tout. Il dépend d'un orchestrateur global qui va lui fournir des APIs pour communiquer avec l'extérieur.
- Dépendances explicites : Un sous-programme doit exprimer les dépendances dont il a besoin pour fonctionner.
- Conteneur IoC : Un conteneur IoC est utilisé pour instancier le sous-programme en prenant en compte ses dépendances.
Formes d'injection de dépendances
L'injection de dépendances peut prendre plusieurs formes :
Lire aussi: Enjeux des Smart Contracts
- Injection par constructeur : Les dépendances sont injectées via le constructeur de la classe.
- Injection par propriété : Les dépendances sont injectées via des propriétés de la classe.
- Injection par champ : Les dépendances sont injectées directement dans des champs privés de la classe.
Injection de dépendances dans ASP.NET Core
Dans ASP.NET Core, l'injection de dépendances est un module principal du framework. Le conteneur IoC est représenté par l'interface IServiceCollection. Pour enregistrer un service dans la collection, il convient de définir la stratégie de gestion de son cycle de vie à adopter :
- Instance : Vous fournissez une instance au conteneur et celui-ci la réutilisera tout le temps.
- Transient : Une nouvelle instance est créée à chaque fois qu'elle est demandée.
- Singleton : Une seule instance est créée pour toute la durée de vie de l'application.
- Scoped : Une instance est créée par portée (par exemple, par requête HTTP dans une application web).
Remplacement du conteneur IoC par défaut
Il est possible de remplacer le conteneur IoC présent par défaut par une autre implémentation. Pour que ce scénario soit possible, il est nécessaire de disposer d'une implémentation des abstractions adaptées au conteneur de votre choix.
Avantages de l'injection de dépendances
L'injection de dépendances offre de nombreux avantages :
- Réduction du couplage : Les classes sont moins dépendantes les unes des autres, ce qui facilite la maintenance et la modification du code.
- Amélioration de la testabilité : Les dépendances peuvent être facilement remplacées par des mocks ou des stubs lors des tests unitaires.
- Amélioration de la réutilisabilité : Les classes peuvent être réutilisées dans différents contextes sans avoir à modifier leur code.
- Amélioration de la maintenabilité : Le code est plus facile à comprendre et à modifier, ce qui réduit les risques d'erreurs.
Combinaison de la personnalisation des contrats JSON et de l'injection de dépendances
La personnalisation des contrats JSON et l'injection de dépendances peuvent être combinées pour créer des applications plus flexibles et maintenables. Par exemple, un résolveur personnalisé de contrats JSON peut être injecté en tant que dépendance dans une classe qui effectue la sérialisation ou la désérialisation JSON. Cela permet de configurer la sérialisation et la désérialisation de manière centralisée et de les adapter aux besoins spécifiques de chaque contexte.
Objets Partiellement Formés
Le concept d'objets partiellement formés soulève des questions intéressantes en matière de conception logicielle. Un objet partiellement formé est un objet qui n'est pas entièrement initialisé et qui peut donc se trouver dans un état invalide.
Lire aussi: NFL : L'influence durable de Mike Alstott
Arguments pour et contre les objets partiellement formés
- Arguments contre : L'idée qu'un constructeur doit toujours renvoyer un objet utilisable est profondément ancrée dans la pensée de nombreux développeurs. Si un objet n'est que partiellement formé au moment où l'on y a accès, cela peut être considéré comme une violation de ce principe. De plus, le fait d'autoriser la manipulation d'objets partiellement formés peut augmenter le risque d'erreurs, car les développeurs peuvent involontairement effectuer des opérations sur un objet dans un état invalide, ce qui peut entraîner un comportement indéfini.
- Arguments pour : Dans certains cas, il peut être nécessaire de subdiviser la formation d'un élément complexe en plusieurs étapes, car toutes les informations nécessaires à la formation totale de cet élément ne sont pas disponibles immédiatement. De plus, dans certains contextes, comme lors de la manipulation de
std::array<T, N>, il peut être pratique queTait un constructeur par défaut sans le coût de l'initialisation.
Programmation par contrat vs programmation défensive
La discussion sur les objets partiellement formés est étroitement liée aux problématiques de la programmation par contrat par rapport à la programmation défensive. La programmation par contrat repose sur l'idée que les fonctions et les classes doivent définir des contrats clairs qui spécifient les conditions préalables, les conditions postérieures et les invariants. La programmation défensive, quant à elle, consiste à vérifier systématiquement les entrées et les sorties d'une fonction ou d'une classe afin de s'assurer qu'elles sont valides.
Défis liés aux objets partiellement formés
Le principal défi lié aux objets partiellement formés est de concilier la nécessité de laisser suffisamment de latitude à l'utilisateur pour terminer la formation de l'élément tout en l'empêchant systématiquement de manipuler cet objet d'une manière qui mènerait à la catastrophe.
Sérialisation
La sérialisation est un processus qui permet de convertir un objet ou un graphe d'objets en un flux de données qui peut être stocké ou transmis. La désérialisation est le processus inverse, qui permet de reconstruire un objet à partir d'un flux de données sérialisé.
Sérialisation en Java
En Java, la sérialisation est un procédé introduit dans le JDK version 1.1 qui permet de rendre un objet ou un graphe d'objets de la JVM persistant pour stockage ou échange et vice versa. L'objet est mis sous une forme sous laquelle il pourra être reconstitué à l'identique.
Défis de la sérialisation
La sérialisation peut poser des défis en termes de sécurité, car le format de sérialisation par défaut est connu et documenté, ce qui permet à des attaquants d'accéder aux données sensibles. De plus, la sérialisation peut limiter les possibilités de changement dans la classe, car la modification de la classe peut rendre les données sérialisées incompatibles.
tags: #c #contract #resolver #private #constructeur #exemple