AIDE .NET

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

Publié avril 3, 2024
Partager:

Introduction au CQRS

CQRS est l'abréviation de Command Query Responsibility Segregation (séparation des responsabilités en matière d'interrogation des commandes). 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(écrit) et les demandes de renseignements(lit)vous pouvez les optimiser indépendamment les uns des autres.

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 allons explorer les concepts du modèle CQRS et du modèleBibliothè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, permettent de récupérer 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 ça marche 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 l'option "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 pouvez avoir une interface ICommandHandler avec une méthode Handle qui prend une commande et exécute l'action. Pour une requête, vous pourriez avoir une interface IQueryHandler avec une méthode Handle qui prend une requête et renvoie des données.

Modèle CQRS C# (Comment ça marche 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 que vous souhaitiez ajouter une tâche(commande) et récupérer les tâches(interrogation).

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);
}
'Define interfaces for your handlers:
Public Interface ICommandHandler(Of TCommand)
	Sub Handle(ByVal command As TCommand)
End Interface
Public Interface IQueryHandler(Of TQuery, TResult)
	Function Handle(ByVal query As TQuery) As TResult
End Interface
VB   C#

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 permettant d'ajouter une tâche à la base de données.

Dans le dossier "Queries", ajoutez une classe GetTasksQuery qui représente une demande de 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;
    }
}
Public Class AddItemCommand
	Public Property Name() As String
	Public Property Quantity() As Integer
	' Constructor
	Public Sub New(ByVal name As String, ByVal quantity As Integer)
		Me.Name = name
		Me.Quantity = quantity
	End Sub
End Class
VB   C#

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
    }
}
Public Class AddItemCommandHandler
	Implements ICommandHandler(Of AddItemCommand)

	Public Sub Handle(ByVal command As AddItemCommand)
		' 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
	End Sub
End Class
VB   C#

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

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" };
        }
    }
}
Imports CQRS_testing.Interfaces

Public Class GetItemsQuery
	' This class might not need any properties, depending on your query
End Class
Namespace CQRS_testing.Queries
	Public Class GetItemsQueryHandler
		Implements IQueryHandler(Of GetItemsQuery, IEnumerable(Of String))

		Public Function Handle(ByVal query As GetItemsQuery) As IEnumerable(Of String)
			' Here, you'd fetch items from your database
			Return New List(Of String) From {"Item1", "Item2"}
		End Function
	End Class
End Namespace
VB   C#

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ée une AddTaskCommand, définit ses propriétés à partir des données du formulaire, puis la transmet à une instance AddTaskCommandHandler pour qu'elle la traite. Pour récupérer les tâches, il appelle un GetTasksQueryHandler pour obtenir les données et les transmettre à 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");
    }
}
Public Class ItemsController
	Inherits Controller

	Private ReadOnly _addItemHandler As ICommandHandler(Of AddItemCommand)
	Private ReadOnly _getItemsHandler As IQueryHandler(Of GetItemsQuery, IEnumerable(Of String))
	' Constructor injection is correctly utilized here
	Public Sub New(ByVal addItemHandler As ICommandHandler(Of AddItemCommand), ByVal getItemsHandler As IQueryHandler(Of GetItemsQuery, IEnumerable(Of String)))
		_addItemHandler = addItemHandler
		_getItemsHandler = getItemsHandler
	End Sub
	Public Function Index() As IActionResult
		' Use the injected _getItemsHandler instead of creating a new instance
		Dim query = New GetItemsQuery()
		Dim items = _getItemsHandler.Handle(query)
		Return View(items)
	End Function
	<HttpPost>
	Public Function Add(ByVal name As String, ByVal quantity As Integer) As IActionResult
		' Use the injected _addItemHandler instead of creating a new instance
		Dim command = New AddItemCommand(name, quantity)
		_addItemHandler.Handle(command)
		Return RedirectToAction("Index")
	End Function
End Class
VB   C#

Pour tout relier, en particulier 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 façon, 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>();
builder.Services.AddTransient(Of ICommandHandler(Of AddItemCommand), AddItemCommandHandler)()
builder.Services.AddTransient(Of IQueryHandler(Of GetItemsQuery, IEnumerable(Of String)), GetItemsQueryHandler)()
VB   C#

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 : Bibliothèque PDF C

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

Explore IronPDF pour la gestion des PDF est un outil destiné aux développeurs travaillant avec le langage de programmation C#, leur permettant de créer, lire et modifier des documents PDF directement dans leurs applications. Cette bibliothèque est conviviale et facilite l'intégration de fonctionnalités PDF telles que la génération de rapports PDF, de factures ou d'autres documentscréer des PDF à partir de HTML code. 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 par sonCapacité de conversion de HTML en PDFla traduction doit être réalisée dans le respect des règles de l'art, en gardant intactes toutes les mises en page et tous les styles. 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");
    }
}
Imports IronPdf

Friend Class Program
	Shared Sub Main(ByVal args() As String)
		Dim renderer = New ChromePdfRenderer()

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

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

		' 3. Convert URL to PDF
		Dim url = "http://ironpdf.com" ' Specify the URL
		Dim pdfFromUrl = renderer.RenderUrlAsPdf(url)
		pdfFromUrl.SaveAs("URLToPDF.pdf")
	End Sub
End Class
VB   C#

Exemple de code

Voyons maintenant comment IronPDF peut être utilisé dans une application C# en suivant la séparation des responsabilités de la requête de commande(CQRS) modèle. 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);
        }
    }
}
Imports IronPdf
Imports System.Threading.Tasks
Namespace PdfGenerationApp.Commands
	Public Class GeneratePdfReportCommand
		' Command handler that generates a PDF report
		Public Async Function GenerateReportAsync(ByVal reportContent As String, ByVal outputPath As String) As Task
			' Initialize the IronPDF HTML to PDF renderer
			Dim renderer = New ChromePdfRenderer()
			' Use IronPDF to generate a PDF from HTML content
			Dim pdf = Await Task.Run(Function() renderer.RenderHtmlAsPdf(reportContent))
			' Save the generated PDF to a specified path
			pdf.SaveAs(outputPath)
		End Function
	End Class
End Namespace
VB   C#

Dans cet exemple, GeneratePdfReportCommand représente une commande dans le modèle CQRS. Il comprend une méthode GenerateReportAsync qui prend reportContent comme une chaîne HTML et un outputPath où le rapport PDF sera sauvegardé. La classe HtmlToPdf d'IronPDF est utilisée pour convertir le contenu HTML au format PDF, qui est ensuite enregistré dans le 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 ça marche pour les développeurs) : Figure 4 - PDF produit

Conclusion

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

En résumé, la requête de commandement Séparation des responsabilités(CQRS) offre une approche structurée pour séparer les responsabilités de lecture et d'écriture des 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. Essayer IronPDF gratuitementvous permettant d'explorer ses capacités avant de vous engager. Pour une utilisation continue, les licences commencent à partir de 399 $, avec différentes options pour répondre aux besoins de votre projet.

< PRÉCÉDENT
En C# (Comment ça marche pour les développeurs)
SUIVANT >
C# Unit Testing (Comment ça marche pour les développeurs)