
Wzorzec CQRS w języku C# (jak działa dla programistów)
Wprowadzenie do CQRS
CQRS to skrót od Command Query Responsibility Segregation (rozdzielenie odpowiedzialności za polecenia i zapytania). Jest to wzorzec, który koncentruje się na oddzieleniu odczytu danych od ich zapisu. To rozróżnienie ma kluczowe znaczenie z kilku powodów. Po pierwsze, umożliwia bardziej elastyczną optymalizację każdej operacji, poprawiając wydajność i skalowalność aplikacji. Gdy rozdzielisz polecenia (zapisy) i zapytania (odczyty), możesz je optymalizować niezależnie.
Na przykład złożona aplikacja może wymagać szybkich operacji odczytu, ale może tolerować wolniejsze operacje zapisu. Stosując CQRS, programiści mogą używać różnych modeli danych do odczytu i zapisu, oddzielając warstwę dostępu do danych, aby dostosować ją do konkretnych potrzeb każdej operacji. W tym artykułe omówimy koncepcje wzorca CQRS oraz bibliotekę *IronPDF dla .NET dla programistów .NET.
Podstawowe pojęcia i komponenty
Istotą CQRS jest rozdzielenie operacji poleceń i zapytań, z których każda obsługuje inne aspekty interakcji z danymi. Zrozumienie tych komponentów ma kluczowe znaczenie dla skutecznego wdrożenia tego wzorca.
-
Polecenia: Odpowiadają za aktualizację danych. Polecenia odzwierciedlają złożoną logikę biznesową i mogą zmieniać stan danych w magazynie danych, działając bez zwracania jakichkolwiek informacji. Polecenia pełnią wyłączną rolę w obsłudze zadań związanych z zapisywaniem danych, bezpośrednio wpływając na stan aplikacji bez generowania żadnego wyniku. Na przykład dodanie nowego użytkownika lub aktualizacja szczegółów istniejącego produktu to czynności wykonywane za pomocą poleceń.
-
Zapytania: Zapytania, zarządzane przez moduł obsługi zapytań, pobierają dane lub obiekty transferu danych bez zmiany stanu systemu. To są pytania, które zadajesz na temat swoich danych. Na przykład pobranie profilu użytkownika lub wyświetlenie listy wszystkich produktów dostępnych w magazynie to zapytania. Zapytania zwracają dane, ale należy upewnić się, że nie modyfikują one danych ani ich stanu.
Jednym z popularnych narzędzi do wdrażania CQRS w aplikacjach .NET jest MediatR, biblioteka wzorców mediatora. Pomaga to zmniejszyć sprzężenie między komponentami aplikacji, umożliwiając im komunikację pośrednią. MediatR ułatwia obsługę poleceń i zapytań, pośrednicząc między poleceniem/zapytaniem a jego obsługującym.
Praktyczna implementacja z wykorzystaniem ASP.NET Core
Wdrożenie wzorca CQRS w .NET Core wymaga skonfigurowania projektu w taki sposób, aby oddzielić polecenia od zapytań, wykorzystując bibliotekę taką jak MediatR do pośredniczenia między nimi. Oto uproszczony przegląd tego, jak skonfigurować CQRS w aplikacji ASP.NET Core.
Krok 1: Skonfiguruj aplikację ASP.NET
-
Uruchom Visual Studio i wybierz opcję utworzenia nowego projektu.
-
Wyszukaj i wybierz typ projektu "Aplikacja internetowa .NET Core". Kliknij Dalej.

-
Nadaj projektowi nazwę i ustaw jego lokalizację. Kliknij Utwórz.
-
Wybierz szablon "Aplikacja internetowa (Model-View-Controller)" dla ASP.NET Core. Upewnij się, że wybierasz wersję .NET Core, która odpowiada Twoim wymaganiom. Kliknij Utwórz.
Krok 2
Następnie warto zorganizować projekt pod kątem CQRS. Można to zrobić, dodając foldery w celu oddzielenia poleceń, zapytań i wspólnych interfejsów, z których będą korzystać. W oknie Solution Explorer kliknij prawym przyciskiem myszy na swój projekt, wybierz "Dodaj", a następnie "Nowy folder". Utwórz trzy foldery: "Commands", "Queries" i "Interfaces".
W folderze "Interfaces" dodaj interfejsy dla swoich poleceń i zapytań. W przypadku polecenia może istnieć interfejs ICommandHandler z metodą Handle, która przyjmuje polecenie i wykonuje działanie. W przypadku zapytania można użyć interfejsu IQueryHandler z metodą Handle, która pobiera zapytanie i zwraca dane.

Krok 3
Teraz dodajmy polecenie i zapytanie, aby to zademonstrować. Załóżmy, że Twoja aplikacja zarządza zadaniami i chcesz dodać zadanie (polecenie) oraz pobrać zadania (zapytanie).
W folderze "Interfaces" dodaj dwa interfejsy:
// 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 InterfaceW folderze "Commands" dodaj klasę AddItemCommand z właściwościami dotyczącymi szczegółów zadania. Dodaj również klasę AddItemCommandHandler, która implementuje interfejs ICommandHandler i zawiera logikę dodawania zadania do bazy danych.
W folderze "Queries" dodaj klasę GetTasksQuery, która reprezentuje żądanie zadań. Dodaj kolejną klasę GetTasksQueryHandler, która implementuje interfejs IQueryHandler i zawiera logikę pobierania zadań z bazy danych.
Prosty przykład: Twój AddItemCommand może wyglądać następująco:
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 ClassA także 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
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 ClassTwoja funkcja GetItemsQuery może być pusta, jeśli nie potrzebuje żadnych parametrów do pobrania zadań, a funkcja GetItemsQueryHandler może wyglądać następująco:
public class GetItemsQuery
{
// This class might not need any properties, depending on your query
}
namespace CQRS_testing.Queries
{
using CQRS_testing.Interfaces;
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 NamespaceW kontrolerach ASP.NET będziesz używać tych procedur obsługi do przetwarzania poleceń i zapytań. Aby dodać zadanie, akcja kontrolera utworzyłaby AddTaskCommand, ustawiła jego właściwości na podstawie danych z formularza, a następnie przekazała go do instancji AddTaskCommandHandler w celu przetworzenia. W celu pobrania zadań wywoływałby on GetTasksQueryHandler, aby uzyskać dane i przekazać je do widoku.
Podłączanie w kontrolerze
Po skonfigurowaniu poleceń i zapytań można teraz używać ich w kontrolerach. Oto jak można to zrobić w klasie 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
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 ClassAby wszystko podłączyć, zwłaszcza jeśli używasz wstrzykiwania zależności (DI) w ASP.NET Core, musisz zarejestrować swoje procedury obsługi poleceń i zapytań w kontenerze DI w pliku Startup.cs. W ten sposób ASP.NET może udostępniać instancje twoich procedur obsługi, gdy są one potrzebne.
Oto bardzo prosty przykład rejestracji procedury obsługi:
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)()W praktycznym zastosowaniu CQRS fundamentalne znaczenie ma rozróżnienie między modelem danych dla operacji zapisu a modelem dla operacji odczytu, co gwarantuje, że architektura obsługuje zróżnicowane i zoptymalizowane podejścia do przetwarzania danych.
IronPDF: biblioteka PDF dla języka C#

Poznaj IronPDF do zarządzania plikami PDF – narzędzie dla programistów pracujących w języku C#, umożliwiające tworzenie, odczytywanie i edytowanie dokumentów PDF bezpośrednio w ich aplikacjach. Ta biblioteka jest przyjazna dla użytkownika, co ułatwia integrację funkcji PDF, takich jak generowanie raportów PDF, faktur lub tworzenie plików PDF z kodu HTML. IronPDF obsługuje różne funkcje, w tym edycję tekstu i obrazów w plikach PDF, konfigurację zabezpieczeń dokumentów oraz konwersję stron internetowych do formatu PDF. Jego wszechstronność i łatwość użytkowania sprawiają, że jest to cenne narzędzie dla programistów pragnących wdrożyć operacje na plikach PDF w swoich projektach.
IronPDF wyróżnia się możliwością konwersji HTML do PDF, zachowując wszystkie układy i style w niezmienionej postaci. Tworzy pliki PDF na podstawie treści internetowych, odpowiednie do raportów, faktur i dokumentacji. Pliki HTML, adresy URL i ciągi znaków HTML można płynnie konwertować do formatu 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 ClassPrzykład kodu
Zobaczmy teraz, jak można wykorzystać IronPDF w aplikacji napisanej w języku C# zgodnie z wzorcem Command Query Responsibility Segregation (CQRS). Poniżej znajduje się uproszczony przykład pokazujący, jak można wykorzystać IronPDF w konfiguracji CQRS do wygenerowania raportu w formacie PDF. Ten przykład ma charakter koncepcyjny i skupia się na generowaniu dokumentu PDF jako polecenia.
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 NamespaceW tym przykładzie GeneratePdfReportCommand reprezentuje polecenie w wzorcu CQRS. Zawiera metodę GenerateReportAsync, która przyjmuje reportContent jako ciąg znaków HTML oraz outputPath, gdzie zostanie zapisany raport PDF. Klasa HtmlToPdf biblioteki IronPDF służy do konwersji treści HTML do formatu PDF, który jest następnie zapisywany w określonej ścieżce. Ta konfiguracja ilustruje, w jaki sposób można zintegrować funkcję generowania plików PDF z architekturą aplikacji, zwłaszcza w scenariuszach wymagających wyraźnego rozdzielenia obszarów odpowiedzialności, zgodnie z zaleceniami CQRS.

Wnioski

Podsumowując, wzorzec Command Query Responsibility Segregation (CQRS) oferuje ustrukturyzowane podejście do rozdzielenia odpowiedzialności za odczyt i zapis danych w aplikacjach. To rozdzielenie nie tylko wyjaśnia architekturę, ale także zwiększa elastyczność, skalowalność i wydajność systemów. Postępując zgodnie z powyższymi wskazówkami, można wdrożyć CQRS w aplikacjach .NET Core, wykorzystując narzędzia takie jak MediatR do usprawnienia komunikacji między poleceniami, zapytaniami i ich obsługami.
Włączenie IronPDF do aplikacji opartej na CQRS jeszcze bardziej rozszerza jej możliwości, umożliwiając łatwe tworzenie, edycję i przechowywanie dokumentów PDF. Niezależnie od tego, czy generujesz raporty, faktury czy jakiekolwiek inne dokumenty, wszechstronne funkcje i prosta składnia IronPDF sprawiają, że jest to potężne narzędzie w Twoim zestawie narzędzi programistycznych. IronPDF oferuje bezpłatną wersję próbną, która pozwala zapoznać się z możliwościami programu przed podjęciem decyzji o zakupie. Dla dalszego użytkowania, licencje zaczynają się od $999, oferując różne opcje dopasowane do potrzeb twojego projektu.

Jacob Mellor jest Chief Technology Officer w Iron Software i wizjonerskim inżynierem, pionierem technologii C# PDF. Jako pierwotny deweloper głównej bazy kodowej Iron Software, kształtuje architekturę produktów firmy od jej początku, przekształcając ją wspólnie z CEO Cameron Rimington w firmę liczącą ponad 50 osób, obsługującą NASA, Teslę i światowe agencje rządowe.
Powiązane artykuły


