.NET ヘルプ

CQRSパターン C#(開発者向けの仕組み)

公開済み 2024年4月3日
共有:

CQRSの紹介

CQRS(コマンドとクエリの責務分離)はコマンドクエリ責任分離を意味します。 データの読み取りと書き込みを分離することに焦点を当てたパターンです。 この区別は幾つかの理由で非常に重要です。 まず、各操作をより柔軟に最適化できるようになり、アプリケーションのパフォーマンスとスケーラビリティが向上します。 コマンドを分離するとき(書き込み)およびクエリ(読み込み)、これらを個別に最適化することができます。

たとえば、複雑なアプリケーションは高速な読み取り操作を必要とする一方で、書き込み操作が遅いことを許容できる場合があります。 CQRSを適用することにより、開発者は読み取りと書き込みのために異なるデータモデルを使用し、それぞれの操作の特定のニーズに合わせてデータアクセス層を分離できます。 この記事では、CQRSパターンの概念とその.NET開発者のためのIronPDFライブラリ.

基本概念とコンポーネント

CQRSの核は、コマンド操作とクエリ操作を分離し、それぞれがデータインタラクションの異なる側面を処理することにあります。 これらのコンポーネントを理解することは、パターンを効果的に実装するために重要です。

  • コマンド: これらはデータを更新する役割を持ちます。 コマンドは複雑なビジネスロジックを体現し、情報を返さずにデータストアのデータ状態を変更することができます。 コマンドは、書き込みデータタスクを処理する独自の役割を担い、出力を生成することなくアプリケーションの状態に直接影響を与えます。 例えば、新しいユーザーを追加することや既存の製品詳細を更新することは、コマンドによって実行されるアクションです。
  • クエリ: クエリは、クエリハンドラーによって管理され、システムの状態を変更することなくデータやデータ転送オブジェクトを取得します。 それらは、データに関してあなたが尋ねる質問です。 例えば、ユーザーのプロファイルを取得することや、在庫にあるすべての商品をリストすることはクエリです。 クエリはデータを返しますが、データやその状態を変更しないことを保証します。

    CQRSを .NETアプリケーションに実装するための人気ツールの一つは、メディエーターパターンライブラリであるMediatRです。 アプリケーションのコンポーネント間の結合を減らし、それらが間接的に通信するのを助けます。 MediatRは、コマンドやクエリとそのハンドラーとの間を仲介することにより、コマンドやクエリの処理を支援します。

ASP.NET Coreによる実践的な実装

ASP.NET CoreでCQRSパターンを実装するには、コマンドとクエリを分離するためにプロジェクトを設定し、それらの間を調停するためにMediatRのようなライブラリを使用します。 以下は、ASP.NET Core アプリケーションで CQRS をセットアップする方法の簡単な概要です。

ステップ1: ASP.NET アプリケーションをセットアップする

  1. Visual Studio を起動して新しいプロジェクトを作成します。

  2. 「ASP.NET Core Web Application」プロジェクトタイプを検索して選択します。 次へ進む。

    CQRS パターン C#(開発者にとっての動作方法):図 1 - 新しい ASP.NET プロジェクトの作成

  3. プロジェクトに名前を付けて、その場所を設定してください。 作成をクリックしてください。

  4. 「ウェブアプリケーション」を選択(モデル-ビュー-コントローラ)"テンプレート for ASP.NET Core." あなたの要件に合った .NET Core バージョンをターゲットにしていることを確認してください。 作成をクリックしてください。

ステップ 2

次に、CQRS用にプロジェクトを整理します。 次の内容を日本語に翻訳してください:

フォルダを追加して、コマンド、クエリ、および共通のインターフェースを分離することができます。 ソリューション エクスプローラーでプロジェクトを右クリックし、「追加」から「新しいフォルダー」に進みます。 「Commands」、「Queries」、「Interfaces」の三つのフォルダを作成してください。

「Interfaces」フォルダーに、コマンドおよびクエリ用のインターフェースを追加します。 コマンドに対しては、ICommandHandlerインターフェースを用い、コマンドを受け取り処理を実行するHandleメソッドを持つことがあります。 クエリの場合、クエリを受け取りデータを返すメソッド Handle を持つインターフェイス IQueryHandler を使用できます。

CQRSパターンC#(開発者のための仕組み):図2 - ファイルの整理例

ステップ3

では、コマンドとクエリを追加してデモを行いましょう。 あなたのアプリケーションがタスクを管理しており、タスクを追加したいと仮定します。(コマンド)タスクの取得(問い合わせ).

「Interfaces」フォルダーに、2つのインターフェースを追加してください。

//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#

「Commands」フォルダーに、タスクの詳細プロパティを持つクラス AddItemCommand を追加します。 さらに、タスクをデータベースに追加するロジックを含む ICommandHandler を実装するクラス AddItemCommandHandler を追加します。

「Queries」フォルダーに、タスクのリクエストを表すクラス GetTasksQuery を追加します。 以下のクラス GetTasksQueryHandler を追加して、IQueryHandler を実装し、データベースからタスクを取得するロジックを含めます。

簡単な例として、AddItemCommand は次のようになります:

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#

そして 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#

あなたのGetItemsQueryは、タスクを取得するためにパラメータを必要としない場合、空になることがあります。そして、GetItemsQueryHandlerは以下のように見えるかもしれません:

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#

ASP.NETコントローラーでは、これらのハンドラーを使用してコマンドやクエリを処理します。 タスクを追加する場合、コントローラーアクションはAddTaskCommandを作成し、フォームデータからそのプロパティを設定し、それを処理するためにAddTaskCommandHandlerインスタンスに渡します。 タスクを取得するためには、GetTasksQueryHandler を呼び出してデータを取得し、それをビューに渡します。

コントローラーに接続する

コマンドとクエリが設定されたら、それらをコントローラーで使用することができます。 以下は、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#

特に依存性注入を使用している場合、すべてを接続するために(DI)ASP.NET Coreでは、Startup.csファイルでコマンドハンドラとクエリハンドラをDIコンテナに登録する必要があります。この方法により、ASP.NETは必要なときにハンドラのインスタンスを提供できます。

こちらはハンドラーを登録する非常に基本的な例です:

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#

CQRSの実際のアプリケーションでは、書き込み操作用のデータモデルと読み取り操作用のデータモデルを区別することが基盤となっており、アーキテクチャがデータ処理の多様で最適化されたアプローチをサポートすることを保証します。

IronPDF: C# PDFライブラリ

CQRSパターン C#(開発者向けの仕組み):図3 - IronPDFウェブページ

PDF管理のためのIronPDFを探求するはC#プログラミング言語を使用する開発者向けのツールであり、アプリケーション内でPDFドキュメントを作成、読み取り、編集することを可能にします。 このライブラリはユーザーフレンドリーであり、PDFレポートや請求書の生成など、PDF機能の統合を簡単にします。**HTMLからPDFを作成するコード IronPDFは、PDF内のテキストや画像の編集、ドキュメントのセキュリティ設定、ウェブページをPDF形式に変換するなど、さまざまな機能をサポートしています。 その多様性と使いやすさにより、プロジェクトにPDF操作を実装しようとする開発者にとって貴重なリソースとなります。

IronPDFは、それ自身での卓越性を発揮します。HTMLからPDFへの変換機能また、すべてのレイアウトとスタイルはそのまま維持してください。 WebコンテンツからPDFを作成し、レポート、請求書、ドキュメントに適しています。 HTMLファイル、URL、およびHTML文字列はシームレスに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");
    }
}
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#

コード例

では、次にCommand Query Responsibility Segregation(コマンドクエリ責任分離)に従ってIronPDFをC#アプリケーション内でどのように活用できるかを探ってみましょう。(CQRS)パターン。 以下は、CQRSセットアップ内でIronPDFを使用してPDFレポートを生成する方法を示す簡単な例です。 この例は概念的なもので、コマンドとしてPDFドキュメントの生成に焦点を当てています。

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#

この例では、GeneratePdfReportCommand は CQRS パターンのコマンドを表します。 HTML文字列としてreportContentを受け取り、PDFレポートが保存されるoutputPathを指定するGenerateReportAsyncメソッドが含まれています。 IronPDFのHtmlToPdfクラスは、HTMLコンテンツをPDF形式に変換し、それを指定されたパスに保存するために使用されます。 このセットアップは、特にCQRSによって推奨される関心の分離が必要なシナリオにおいて、PDF生成機能をアプリケーションのアーキテクチャに統合する方法を示しています。

CQRSパターン C#(開発者向けの仕組み):図4 - 出力されたPDF

結論

CQRSパターンC#(開発者のための仕組み):図5 - IronPDFライセンス情報

締めくくりとして、コマンドとクエリの責務分離 (Command Query Responsibility Segregation)(CQRS)パターンは、アプリケーションにおいてデータを読み書きする責任を分離するための構造化されたアプローチを提供します。 この分離はアーキテクチャを明確にするだけでなく、システムの柔軟性、スケーラビリティ、およびパフォーマンスも向上させます。 上記の手順に従うことで、MediatRのようなツールを使用して、コマンド、クエリ、およびそのハンドラー間の通信を効率化しながら、ASP.NET CoreアプリケーションにCQRSを実装できます。

IronPDFをCQRSベースのアプリケーションに統合することにより、その機能がさらに拡張され、PDFドキュメントの作成、操作、および保存を簡単に行うことができます。 レポート、請求書、または任意の形式のドキュメントを生成する際、IronPDF の包括的な機能とシンプルな構文は、開発ツールキットにおいて強力なツールとなります。 **IronPDFを無料でお試しください。その機能を試す機会を提供し、コミットメントする前に探求することができます。 継続的な使用については、ライセンスは399ドルからで、プロジェクトのニーズに合わせてさまざまなオプションを提供しています。

< 以前
C#での動作方法(開発者向け)
次へ >
C# 単体テスト (開発者はどのように機能するか)