.NET幫助 CQRS Pattern C#(對於開發者的運行原理) Curtis Chau 更新日期:7月 28, 2025 Download IronPDF NuGet 下載 DLL 下載 Windows 安裝程式 Start Free Trial Copy for LLMs Copy for LLMs Copy page as Markdown for LLMs Open in ChatGPT Ask ChatGPT about this page Open in Gemini Ask Gemini about this page Open in Grok Ask Grok about this page Open in Perplexity Ask Perplexity about this page Share Share on Facebook Share on X (Twitter) Share on LinkedIn Copy URL Email article 介紹 CQRS CQRS 代表命令查詢責任分離。 這種模式專注於將數據的讀取和寫入分開。 這種區分對於多個理由至關重要。 首先,它允許對每個操作進行更靈活的優化,從而改善應用程式的性能和可擴展性。 當您分開命令(寫入)和查詢(讀取)時,您可以獨立優化它們。 例如,復雜的應用程式可能需要快速的讀取操作,但可以容忍較慢的寫入操作。 通過應用 CQRS,開發人員可以對讀寫使用不同的數據模型,分隔數據訪問層以滿足每個操作的具體需求。 在本文中,我們將探索 CQRS 模式的概念和 *IronPDF for .NET 開發者的庫。 核心概念和組件 CQRS 的核心在於分離命令和查詢操作,每個操作處理數據交互的不同方面。 理解這些組件對於有效執行這個模式至關重要。 命令:這些負責更新數據。 命令體現了複雜的商業邏輯,可以通過行動改變數據存儲總的數據狀態,而不返回任何信息。 命令專門負責處理寫入數據的任務,直接影響應用程式的狀態而不產生任何輸出。 例如,添加新用戶或更新現有產品詳情是由命令執行的操作。 查詢:查詢由查詢處理器管理,負責檢索數據或數據傳輸對象而不改變系統的狀態。 它們是您對數據的疑問。 例如,獲取用戶檔案或列出庫存中所有可用產品都是查詢。 查詢返回數據但確保不會修改數據或其狀態。 在 .NET 應用中實現 CQRS 的一個流行工具是 MediatR,一個中介者模式庫。 它有助於減少應用程式各個組件之間的耦合,使它們間接地進行通信。 MediatR 通過在命令/查詢和其處理器之間進行中介,來促進命令和查詢的處理。 使用 ASP.NET Core 的實施 在 ASP.NET Core 中實施 CQRS 模式涉及設置您的專案以分離命令和查詢,使用像 MediatR 這樣的庫來進行中介。 這裡是如何在您的 ASP.NET Core 應用中設置 CQRS 的簡化概述。 步驟 1:設置您的 ASP.NET 應用 打開 Visual Studio,選擇創建一個新項目。 搜索並選擇 "ASP.NET Core Web Application" 項目類型。 單擊下一步。 給您的項目命名並設置其位置。 點擊創建。 為 ASP.NET Core 選擇 "Web 應用(模型-視圖-控制器)" 模板。 確保您面向符合您需求的 .NET Core 版本。 點擊創建。 步驟 2 接下來,您需要為 CQRS 組織您的項目。 您可以通過添加文件夾來分隔命令、查詢和它們將使用的公共介面。 在“解決方案資源管理器”中,右鍵單擊您的項目,選擇“添加”,然後選擇“新建文件夾”。 創建三個文件夾:“Commands”、“Queries”和“Interfaces”。 在“Interfaces”文件夾中,為您的命令和查詢添加介面。 對於命令,您可能有一個名為 ICommandHandler 的介面,其內含接收命令並執行動作的方法 Handle。 對於查詢,您可以有一個名為 IQueryHandler 的介面,其中有接收查詢並返回數據的方法 Handle。 步驟 3 現在讓我們添加一個命令和查詢以示範。 假設您的應用程序管理任務,而您希望添加一個任務(命令)並檢索任務(查詢)。 在“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 $vbLabelText $csharpLabel 在“Commands”文件夾中,添加一個名為 AddItemCommand 的類,其中包含任務詳情的屬性。 還要添加一個實施 ICommandHandler 的類 AddItemCommandHandler,其中包含將任務添加到數據庫的邏輯。 在“Queries”文件夾中,添加一個類 GetTasksQuery,它代表對任務的請求。 添加另一個實現 IQueryHandler 的類 GetTasksQueryHandler,其中包含從數據庫檢索任務的邏輯。 對於一個簡單的示例,您的 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 $vbLabelText $csharpLabel 而 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 $vbLabelText $csharpLabel 您的 GetItemsQuery 可以是空的,如果它不需要任何參數來取任務,GetItemsQueryHandler 可能看起來像這樣: 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" }; } } } 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 Namespace $vbLabelText $csharpLabel 在您的 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 $vbLabelText $csharpLabel 將一切接線起來,特別是如果您在 ASP.NET Core 中使用依賴注入 (DI),您需要在 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)() $vbLabelText $csharpLabel 在 CQRS 的實際應用中,寫入操作和讀取操作的數據模型之間的區別是基礎,確保架構支持多種且優化的數據處理方式。 IronPDF:C# PDF 庫 探索 IronPDF 用於 PDF 管理 是一個面向 C# 程式設計語言開發者的工具,使它們能夠直接在應用中創建、讀取和編輯 PDF 文檔。 此庫用戶友好,使其更容易集成 PDF 功能,比如生成 PDF 報告、發票或從 HTML 創建 PDF代碼。 IronPDF 支持多種功能,包括編輯 PDF 中的文本和圖像、設置文檔安全性以及將網頁轉換為 PDF 格式。 其多功能性和易用性使其成為開發者希望在項目中實施 PDF 操作的寶貴資源。 IronPDF 以其HTML 到 PDF 轉換功能而出色,保持所有佈局和樣式完整。 它可以從網頁內容創建 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 $vbLabelText $csharpLabel 代碼示例 現在,讓我們探索如何在遵循命令查詢責任分離(CQRS)模式的 C# 應用中使用 IronPDF。 以下是一個簡化的示例,展示了如何在 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 $vbLabelText $csharpLabel 在這個例子中,GeneratePdfReportCommand 代表 CQRS 模式中的一個命令。 它包含一個 GenerateReportAsync 方法,該方法接收作為 HTML 字符串的 reportContent 和保存 PDF 報告的 outputPath。 IronPDF 的 HtmlToPdf 類用於將 HTML 內容轉換為 PDF 格式,隨後保存到指定路徑。 此設置說明了如何將 PDF 生成功能集成到您的應用程序架構中,特別是在需要明確的關注點分離的情況下,如 CQRS 所推廣的。 結論 總結,命令查詢責任分離(CQRS)模式提供了一種將數據讀寫責任分開的結構化方法。 這種分離不僅明確了架構,還提升了系統的靈活性、可擴展性和性能。 通過遵循上述步驟,您可以在 ASP.NET Core 應用中實施 CQRS,使用像 MediatR 這樣的工具來簡化命令、查詢及其處理程序之間的通信。 將 IronPDF 集成到您的基於 CQRS 的應用中進一步擴大其能力,使您能夠輕鬆創建、操作和存儲 PDF 文檔。 無論您是生成報告、發票或任何形式的文檔,IronPDF 的全面功能和簡潔語法都使其成為開發工具箱中的強大工具。 IronPDF 提供免費試用,讓您在承諾前探索其能力。 續約使用的許可證從 $799 起提供,提供多種選項以符合您的項目需求。 常見問題解答 什麼是軟體開發中的 CQRS 模式? CQRS 模式,即指令查詢責任分離,是一種將應用程式中的資料讀取與寫入分離的設計策略。這種分離允許指令(寫入)和查詢(讀取)操作的獨立優化,提高了效能和擴展性。 CQRS 如何提高 .NET 應用程式的效能? CQRS 通過為讀寫操作使用不同的資料模型來提高 .NET 應用程式的效能,使開發者可以獨立優化每個部分。這提高了處理複雜業務邏輯的可擴展性和效率。 在 CQRS 設置中使用 MediatR 有什麼優勢? MediatR 是一個中介者模式庫,可以通過減少 .NET 應用程式中元件之間的耦合來促進 CQRS。它作為一個中介,管理指令、查詢及其處理器之間的互動。 IronPDF 如何在 C# 應用程式中補充 CQRS 模式? IronPDF 通過提供強大的 PDF 操作功能來補充 CQRS 模式。它允許開發者在應用程式中生成、讀取和編輯 PDF 檔案,非常適合在 CQRS 設置中作為指令操作的一部分來創建 PDF 報告。 為何在 ASP.NET Core 專案中分離指令和查詢是有益的? 在 ASP.NET Core 專案中分離指令和查詢可以增強組織性和清晰度。它允許開發者獨立管理每個方面,提高了可維護性並符合 CQRS 模式的原則。 依賴注入在 CQRS 架構中扮演什麼角色? 依賴注入在 CQRS 架構中至關重要,因為它允許無縫註冊和提供指令和查詢處理器。這確保 ASP.NET Core 應用程式能有效地解析依賴關係並根據需要管理處理器的實例。 如何在 C# 中使用庫將 HTML 轉換為 PDF? 您可以使用 IronPDF 的 RenderHtmlAsPdf 方法將 HTML 字串轉換為 PDF。它還支援使用 RenderHtmlFileAsPdf 將 HTML 文件轉換為 PDF,這對於生成報告和文件非常有用。 我可以在購買前評估 C# 的 PDF 库嗎? 是的,IronPDF 提供免費的試用版,讓開發者在購買決策前探索其功能和特性。 Curtis Chau 立即與工程團隊聊天 技術作家 Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。 相關文章 更新日期 9月 4, 2025 RandomNumberGenerator C# 使用RandomNumberGenerator C#類可以幫助將您的PDF生成和編輯項目提升至新水準 閱讀更多 更新日期 9月 4, 2025 C#字符串等於(它如何對開發者起作用) 當結合使用強大的PDF庫IronPDF時,開關模式匹配可以讓您構建更智能、更清晰的邏輯來進行文檔處理 閱讀更多 更新日期 8月 5, 2025 C#開關模式匹配(對開發者來說是如何工作的) 當結合使用強大的PDF庫IronPDF時,開關模式匹配可以讓您構建更智能、更清晰的邏輯來進行文檔處理 閱讀更多 在 C# 中(對於開發者的運行原理)C# 單元測試(對於開發者...