AIDE .NET

Modèle CQRS C# (Comment ça marche pour les développeurs)

Chaknith Bin
Chaknith Bin
avril 3, 2024
Partager:

Introduction au CQRS

CQRS signifie Segregation des Responsabilités de Commande et de Requête. Il s'agit d'un modèle qui vise à séparer la lecture des données de leur écriture. Cette distinction est cruciale pour plusieurs raisons. Premièrement, il permet une optimisation plus souple de chaque opération, améliorant ainsi les performances et l'évolutivité de l'application. Lorsque vous séparez les commandes (écritures) et les requêtes (lectures), vous pouvez les optimiser indépendamment.

Par exemple, une application complexe peut nécessiter des opérations de lecture rapides mais peut tolérer des opérations d'écriture plus lentes. En appliquant le CQRS, les développeurs peuvent utiliser des modèles de données différents pour les lectures et les écritures, en séparant la couche d'accès aux données pour l'adapter aux besoins spécifiques de chaque opération. Dans cet article, nous explorerons les concepts du modèle CQRS et la bibliothèque IronPDF pour les développeurs .NET.

Concepts et composants fondamentaux

Le cœur du CQRS réside dans la séparation des opérations de commande et d'interrogation, chacune traitant des aspects différents de l'interaction avec les données. Il est essentiel de comprendre ces éléments pour mettre en œuvre le modèle de manière efficace.

  • Commandes : Elles sont responsables de la mise à jour des données. Les commandes intègrent une logique commerciale complexe et peuvent modifier l'état des données dans le magasin de données en agissant sans renvoyer d'informations. Les commandes ont pour rôle exclusif de gérer les tâches d'écriture de données, influençant directement l'état de l'application sans produire de résultats. Par exemple, l'ajout d'un nouvel utilisateur ou la mise à jour des détails d'un produit existant sont des actions exécutées par des commandes.
  • Requêtes : Les requêtes, gérées par un gestionnaire de requêtes, récupèrent des données ou des objets de transfert de données sans modifier l'état du système. Ce sont les questions que vous posez sur vos données. Par exemple, la recherche du profil d'un utilisateur ou la liste de tous les produits disponibles dans un inventaire sont des requêtes. Les requêtes renvoient des données mais garantissent qu'elles ne modifient pas les données ou leur état.

    L'un des outils les plus populaires pour mettre en œuvre le CQRS dans les applications .NET est MediatR, une bibliothèque de modèles de médiateurs. Il permet de réduire le couplage entre les composants d'une application, en les faisant communiquer indirectement. MediatR facilite le traitement des commandes et des requêtes en jouant le rôle de médiateur entre la commande/requête et son gestionnaire.

Mise en œuvre pratique avec ASP.NET Core

La mise en œuvre du modèle CQRS dans ASP.NET Core implique de configurer votre projet de manière à séparer les commandes et les requêtes, en utilisant une bibliothèque comme MediatR pour assurer la médiation entre les deux. Voici un aperçu simplifié de la manière dont vous pouvez configurer le CQRS dans votre application ASP.NET Core.

Étape 1 : Configurer votre application ASP.NET

  1. Démarrez Visual Studio et choisissez de créer un nouveau projet.

  2. Recherchez et sélectionnez un type de projet "Application Web ASP.NET Core". Cliquez sur Suivant.

    Modèle CQRS C# (Comment cela fonctionne pour les développeurs) : Figure 1 - Création d'un nouveau projet ASP.NET

  3. Donnez un nom à votre projet et définissez son emplacement. Cliquez sur Créer.

  4. Choisissez le modèle "Application Web (Modèle-Vue-Contrôleur)" pour ASP.NET Core. Assurez-vous de cibler la version de .NET Core qui correspond à vos besoins. Cliquez sur Créer.

Étape 2

Ensuite, vous devez organiser votre projet pour le CQRS. Vous pouvez le faire en ajoutant des dossiers pour séparer les commandes, les requêtes et les interfaces communes qu'ils utiliseront. Dans l'explorateur de solutions, faites un clic droit sur votre projet, cliquez sur "Ajouter", puis sur "Nouveau dossier". Créez trois dossiers : "Commandes", "Requêtes" et "Interfaces".

Dans le dossier "Interfaces", ajoutez des interfaces pour vos commandes et vos requêtes. Pour une commande, vous pourriez avoir une interface ICommandHandler avec une méthode Handle qui prend une commande et effectue l'action. Pour une requête, vous pourriez avoir une interface IQueryHandler avec une méthode Handle qui prend une requête comme paramètre et renvoie des données.

Modèle CQRS C# (Comment cela fonctionne pour les développeurs) : Figure 2 - Exemple d'organisation des fichiers

Étape 3

Ajoutons maintenant une commande et une requête pour faire une démonstration. Supposons que votre application gère des tâches, et vous souhaitez ajouter une tâche (commande) et récupérer des tâches (requête).

Dans le dossier "Interfaces", ajoutez deux interfaces :

//Define interfaces for your handlers:
public interface ICommandHandler<TCommand>
{
    void Handle(TCommand command);
}
public interface IQueryHandler<TQuery, TResult>
{
    TResult Handle(TQuery query);
}
//Define interfaces for your handlers:
public interface ICommandHandler<TCommand>
{
    void Handle(TCommand command);
}
public interface IQueryHandler<TQuery, TResult>
{
    TResult Handle(TQuery query);
}

Dans le dossier "Commands", ajoutez une classe AddItemCommand avec des propriétés pour les détails de la tâche. Ajoutez également une classe AddItemCommandHandler qui implémente ICommandHandler et contient la logique pour ajouter une tâche à la base de données.

Dans le dossier "Queries", ajoutez une classe GetTasksQuery qui représente une requête pour des tâches. Ajoutez une autre classe GetTasksQueryHandler qui implémente IQueryHandler et contient la logique pour récupérer les tâches de la base de données.

Pour un exemple simple, votre AddItemCommand pourrait ressembler à ceci :

public class AddItemCommand
{
    public string Name { get; set; }
    public int Quantity { get; set; }
    // Constructor
    public AddItemCommand(string name, int quantity)
    {
        Name = name;
        Quantity = quantity;
    }
}
public class AddItemCommand
{
    public string Name { get; set; }
    public int Quantity { get; set; }
    // Constructor
    public AddItemCommand(string name, int quantity)
    {
        Name = name;
        Quantity = quantity;
    }
}

Et le AddItemCommandHandler :

public class AddItemCommandHandler : ICommandHandler<AddItemCommand>
{
    public void Handle(AddItemCommand command)
    {
        // Here, you'd add the item to your database, for example, to have employee data stored
        Console.WriteLine($"Adding item: {command.Name} with quantity {command.Quantity}");
        // Add database logic here
    }
}
public class AddItemCommandHandler : ICommandHandler<AddItemCommand>
{
    public void Handle(AddItemCommand command)
    {
        // Here, you'd add the item to your database, for example, to have employee data stored
        Console.WriteLine($"Adding item: {command.Name} with quantity {command.Quantity}");
        // Add database logic here
    }
}

Votre GetItemsQuery pourrait être vide s'il n'a pas besoin de paramètres pour récupérer des tâches, et GetItemsQueryHandler pourrait ressembler à :

public class GetItemsQuery
{
    // This class might not need any properties, depending on your query
}
using CQRS_testing.Interfaces;
namespace CQRS_testing.Queries
{
    public class GetItemsQueryHandler : IQueryHandler<GetItemsQuery, IEnumerable<string>>
    {
        public IEnumerable<string> Handle(GetItemsQuery query)
        {
            // Here, you'd fetch items from your database
            return new List<string> { "Item1", "Item2" };
        }
    }
}
public class GetItemsQuery
{
    // This class might not need any properties, depending on your query
}
using CQRS_testing.Interfaces;
namespace CQRS_testing.Queries
{
    public class GetItemsQueryHandler : IQueryHandler<GetItemsQuery, IEnumerable<string>>
    {
        public IEnumerable<string> Handle(GetItemsQuery query)
        {
            // Here, you'd fetch items from your database
            return new List<string> { "Item1", "Item2" };
        }
    }
}

Dans vos contrôleurs ASP.NET, vous utiliserez ces gestionnaires pour traiter les commandes et les requêtes. Pour ajouter une tâche, l'action du contrôleur créerait une AddTaskCommand, définirait ses propriétés à partir des données du formulaire, puis la transmettrait à une instance de AddTaskCommandHandler pour la traiter. Pour récupérer des tâches, il appellerait un GetTasksQueryHandler pour obtenir les données et les passer à la vue.

Câblage d'un contrôleur

Une fois vos commandes et vos requêtes configurées, vous pouvez maintenant les utiliser dans vos contrôleurs. Voici comment vous pourriez le faire dans une classe ItemsController :

public class ItemsController : Controller
{
    private readonly ICommandHandler<AddItemCommand> _addItemHandler;
    private readonly IQueryHandler<GetItemsQuery, IEnumerable<string>> _getItemsHandler;
    // Constructor injection is correctly utilized here
    public ItemsController(ICommandHandler<AddItemCommand> addItemHandler, IQueryHandler<GetItemsQuery, IEnumerable<string>> getItemsHandler)
    {
        _addItemHandler = addItemHandler;
        _getItemsHandler = getItemsHandler;
    }
    public IActionResult Index()
    {
        // Use the injected _getItemsHandler instead of creating a new instance
        var query = new GetItemsQuery();
        var items = _getItemsHandler.Handle(query);
        return View(items);
    }
    [HttpPost]
    public IActionResult Add(string name, int quantity)
    {
        // Use the injected _addItemHandler instead of creating a new instance
        var command = new AddItemCommand(name, quantity);
        _addItemHandler.Handle(command);
        return RedirectToAction("Index");
    }
}
public class ItemsController : Controller
{
    private readonly ICommandHandler<AddItemCommand> _addItemHandler;
    private readonly IQueryHandler<GetItemsQuery, IEnumerable<string>> _getItemsHandler;
    // Constructor injection is correctly utilized here
    public ItemsController(ICommandHandler<AddItemCommand> addItemHandler, IQueryHandler<GetItemsQuery, IEnumerable<string>> getItemsHandler)
    {
        _addItemHandler = addItemHandler;
        _getItemsHandler = getItemsHandler;
    }
    public IActionResult Index()
    {
        // Use the injected _getItemsHandler instead of creating a new instance
        var query = new GetItemsQuery();
        var items = _getItemsHandler.Handle(query);
        return View(items);
    }
    [HttpPost]
    public IActionResult Add(string name, int quantity)
    {
        // Use the injected _addItemHandler instead of creating a new instance
        var command = new AddItemCommand(name, quantity);
        _addItemHandler.Handle(command);
        return RedirectToAction("Index");
    }
}

Pour tout configurer, surtout si vous utilisez l'injection de dépendances (DI) dans ASP.NET Core, vous devrez enregistrer vos gestionnaires de commandes et de requêtes avec le conteneur DI dans le fichier Startup.cs. De cette manière, ASP.NET peut fournir des instances de vos gestionnaires lorsqu'elles sont nécessaires.

Voici un exemple très simple d'enregistrement d'un gestionnaire :

builder.Services.AddTransient<ICommandHandler<AddItemCommand>, AddItemCommandHandler>();
builder.Services.AddTransient<IQueryHandler<GetItemsQuery, IEnumerable<string>>, GetItemsQueryHandler>();
builder.Services.AddTransient<ICommandHandler<AddItemCommand>, AddItemCommandHandler>();
builder.Services.AddTransient<IQueryHandler<GetItemsQuery, IEnumerable<string>>, GetItemsQueryHandler>();

Dans l'application pratique du CQRS, la distinction entre le modèle de données pour les opérations d'écriture et celui pour les opérations de lecture est fondamentale, car elle garantit que l'architecture prend en charge des approches variées et optimisées pour le traitement des données.

IronPDF : C&num ; Bibliothèque PDF

Modèle CQRS C# (Comment ça fonctionne pour les développeurs) : Figure 3 - Page Web IronPDF

Explorez IronPDF pour la gestion des PDF est un outil pour les développeurs travaillant avec le langage de programmation C#, leur permettant de créer, lire et éditer des documents PDF directement dans leurs applications. Cette bibliothèque est conviviale, simplifiant l'intégration des fonctionnalités PDF telles que la génération de rapports PDF, de factures ou la création de PDF à partir de code HTML. IronPDF prend en charge diverses fonctionnalités, notamment l'édition de texte et d'images dans les PDF, la mise en place d'une sécurité des documents et la conversion de pages web au format PDF. Sa polyvalence et sa facilité d'utilisation en font une ressource précieuse pour les développeurs qui cherchent à mettre en œuvre des opérations PDF dans leurs projets.

IronPDF excelle avec sa capacité de conversion de HTML en PDF, en conservant tous les mises en page et styles intacts. Il crée des PDF à partir de contenus web, adaptés aux rapports, aux factures et à la documentation. Les fichiers HTML, les URL et les chaînes HTML peuvent être convertis en PDF de manière transparente.

using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}

Exemple de code

Maintenant, explorons comment IronPDF peut être utilisé dans une application C# en suivant le modèle de séparation des responsabilités Command Query Responsibility Segregation (CQRS). Vous trouverez ci-dessous un exemple simplifié de l'utilisation d'IronPDF dans le cadre d'une configuration CQRS pour générer un rapport PDF. Cet exemple est conceptuel et se concentre sur la génération d'un document PDF en tant que commande.

using IronPdf;
using System.Threading.Tasks;
namespace PdfGenerationApp.Commands
{
    public class GeneratePdfReportCommand
    {
        // Command handler that generates a PDF report
        public async Task GenerateReportAsync(string reportContent, string outputPath)
        {
            // Initialize the IronPDF HTML to PDF renderer
            var renderer = new ChromePdfRenderer();
            // Use IronPDF to generate a PDF from HTML content
            var pdf = await Task.Run(() => renderer.RenderHtmlAsPdf(reportContent));
            // Save the generated PDF to a specified path
            pdf.SaveAs(outputPath);
        }
    }
}
using IronPdf;
using System.Threading.Tasks;
namespace PdfGenerationApp.Commands
{
    public class GeneratePdfReportCommand
    {
        // Command handler that generates a PDF report
        public async Task GenerateReportAsync(string reportContent, string outputPath)
        {
            // Initialize the IronPDF HTML to PDF renderer
            var renderer = new ChromePdfRenderer();
            // Use IronPDF to generate a PDF from HTML content
            var pdf = await Task.Run(() => renderer.RenderHtmlAsPdf(reportContent));
            // Save the generated PDF to a specified path
            pdf.SaveAs(outputPath);
        }
    }
}

Dans cet exemple, GeneratePdfReportCommand représente une commande dans le modèle CQRS. Il comprend une méthode GenerateReportAsync qui prend en entrée reportContent en tant que chaîne HTML et un outputPath où le rapport PDF sera enregistré. La classe HtmlToPdf d'IronPDF est utilisée pour convertir le contenu HTML au format PDF, qui est ensuite enregistré au chemin spécifié. Cette configuration illustre la manière dont vous pouvez intégrer la fonctionnalité de génération de PDF dans l'architecture de votre application, en particulier dans les scénarios nécessitant une séparation claire des préoccupations, comme le préconise le CQRS.

Modèle CQRS C# (Comment cela fonctionne pour les développeurs) : Figure 4 - PDF exporté

Conclusion

Modèle CQRS C# (Comment cela fonctionne pour les développeurs) : Figure 5 - Informations sur la licence IronPDF

Pour conclure, le pattern Segregation des Responsabilités Commande-Requête (CQRS) offre une approche structurée pour séparer les responsabilités de lecture et d'écriture de données dans vos applications. Cette séparation permet non seulement de clarifier l'architecture, mais aussi d'améliorer la flexibilité, l'évolutivité et les performances de vos systèmes. En suivant les étapes décrites ci-dessus, vous pouvez mettre en œuvre le CQRS dans vos applications ASP.NET Core, en utilisant des outils comme MediatR pour rationaliser la communication entre les commandes, les requêtes et leurs gestionnaires.

L'intégration d'IronPDF à votre application basée sur le CQRS élargit encore ses capacités, vous permettant de créer, manipuler et stocker des documents PDF sans effort. Que vous produisiez des rapports, des factures ou toute autre forme de document, les fonctionnalités complètes et la syntaxe simple d'IronPDF en font un outil puissant dans votre boîte à outils de développement. IronPDF offre une version d'essai gratuite, vous donnant la possibilité d'explorer ses capacités avant de vous engager. Pour un usage continu, les licences commencent à partir de $749, offrant diverses options pour répondre aux besoins de votre projet.

Chaknith Bin
Ingénieur logiciel
Chaknith travaille sur IronXL et IronBarcode. Il possède une expertise approfondie en C# et .NET, aidant à améliorer le logiciel et à soutenir les clients. Ses idées issues des interactions avec les utilisateurs contribuent à de meilleurs produits, une documentation améliorée et une expérience globale enrichie.
< PRÉCÉDENT
En C# (Comment ça marche pour les développeurs)
SUIVANT >
C# Unit Testing (Comment ça marche pour les développeurs)