{"id":81017,"date":"2018-09-26T17:18:38","date_gmt":"2018-09-26T17:18:38","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=81017"},"modified":"2026-04-15T18:35:08","modified_gmt":"2026-04-15T18:35:08","slug":"getting-started-with-cqrs-part-1","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/getting-started-with-cqrs-part-1\/","title":{"rendered":"Getting Started with CQRS in ASP.NET Core: MongoDB, RabbitMQ, and SQLite"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"h-executive-summary\">Executive Summary<\/h2>\n\n\n\n<p><strong>CQRS (Command Query Responsibility Segregation) separates the read side (queries) and write side (commands) of an application into distinct models and datastores. This enables independent scaling, different optimisation strategies for reads vs writes, and a cleaner separation of concerns than a standard CRUD architecture. This series implements CQRS in ASP.NET Core with a practical three-component stack: MongoDB as the query datastore (flexible document model for read-optimised views), RabbitMQ as the message broker (decoupling command events from their effects), and SQLite as the command datastore (reliable writes for the command side). Part 1 covers installing and configuring all three components, creating the ASP.NET Core project, integrating SQLite, and building the first API controller facade.<\/strong><\/p>\n\n\n<p><strong>The series so far:<\/strong><\/p>\n<ol>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/dotnet\/c-programming\/getting-started-with-cqrs-part-1\/\">Getting Started with CQRS \u2013 Part 1<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/dotnet\/c-programming\/getting-started-with-cqrs-part-2\/\">Getting Started with CQRS \u2013 Part 2<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/dotnet\/c-programming\/getting-started-with-cqrs-part-3\/\">Getting Started with CQRS \u2013 Part 3<\/a><\/li>\n<\/ol>\n\n\n\n\n<p>Most developers are used to creating and handling CRUD (create, read, update, delete) systems for operations that divide tasks into updating and searching for data. When it comes to the problems this kind of well-known practice causes when considering the huge number of different frameworks, solutions, and infrastructural issues that arise every day, the life of those same developers can get tricky.<\/p>\n\n\n\n<p>One of the main concerns regarding this is the increasing number of representations that your models can have when the application must serve more and more clients. Most of the time, the architectural design of the applications is made in the common CRUD-like way, that is, a single database (whether it is relational or not) that\u2019ll both store and serve as the querying center of all requirements.<\/p>\n\n\n\n<p>That concern about aligning these worlds every time a new microservice is born, for example, ties the developer\u2019s hands to create each side in a more specialized manner when it comes to performance issues, object model complexities, resilience, and scalability independence, etc.<\/p>\n\n\n\n<p>The term <strong>CQRS<\/strong>, (<em>Command Query Responsibility Segregation) <\/em>is based on the <a href=\"https:\/\/martinfowler.com\/bliki\/CommandQuerySeparation.html\">famous CQS idea<\/a>. It is the closest architecture available to split these responsibilities to accomplish more and simplify the design. It\u2019s all about separating things, especially if they\u2019re very different conceptually when it comes to reading and updating models.<\/p>\n\n\n\n<p>The pattern basically divides into two categories:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><em>Queries:<\/em> get the information only, and never change anything within the model;<\/li>\n\n\n\n<li><em>Commands:<\/em> that\u2019s when you perform the writes, updates, and deletes (along with all the logic\u2019s complexities inherent to the business rules).<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Figure 1 illustrates how this communication usually happens. Notice, specifically, the event sync in white that\u2019ll take the written model data and send it asynchronously to another module in order to save the same data to the materialized view (NoSQL database, in this case).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1298\" height=\"715\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/09\/word-image-237.png\" alt=\"\" class=\"wp-image-81018\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"caption\">Figure 1. CQRS architectural representation.<\/p>\n\n\n\n<p>CQRS goes a bit further allowing you to have both worlds deployed and working structurally and physically separated from each other, even on different hardware, cloud, etc. There\u2019s a lot of flexibility here since you can define your own toolset, along with event-driven and message-driven architectures, DDD, etc. to make it more dynamic depending on your reality.<\/p>\n\n\n\n<p>In this series, you\u2019ll learn how to create and gradually enhance one basic CQRS-like application, created upon ASP.NET Core. It consists of a Web API, a REST web service that will deal with customers data in a CRUD fashion, however, sending each of the commands to its respective handler. Then, you can decide where to manage the data flows: whether it is on the command or query\u2019s database\/datastore.<\/p>\n\n\n\n<p>In this first part of the article, you\u2019ll get started with the project setups. The project relies on a REST-like application that handles customer information (basically user\u2019s data and a list of phones) to demonstrate how a single model lives within a CQRS structure.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-setting-up-the-environment\">Setting up the environment<\/h2>\n\n\n\n<p>The first thing you must install is the latest version of Visual Studio (the Community edition is good to go). For this article, Visual Studio 2017 is the chosen version, since it is the latest. The prerequisites consist of two workloads:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>ASP.NET and web development;<\/li>\n\n\n\n<li>.NET Core cross-platform development.<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Also, make sure that the <a href=\"https:\/\/www.microsoft.com\/net\/download\">.NET Core SDK<\/a> (latest version) is properly installed on your machine.<\/p>\n\n\n\n<p>If you have already installed VS, you can <a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/install\/modify-visual-studio\">change the IDE setup<\/a> by launching the installer, running it again, and selecting the proper workloads.<\/p>\n\n\n\n<p><strong>Setting up SQLite<\/strong><\/p>\n\n\n\n<p>SQLite is used as the relational database to store the customer&#8217;s data \u2013 the \u2018write\u2019 side of the project. First, <a href=\"http:\/\/sqlitebrowser.org\/\">go to the download page of DB Browser<\/a> (a famous GUI tool to manage the SQLite databases) and install it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-setting-up-mongodb\">Setting up MongoDB<\/h2>\n\n\n\n<p>For the querying side of the model, we\u2019ll use MongoDB as the database. First of all, you need to <a href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/install-mongodb-on-windows\/#install-mongodb-community-edition-on-windows\">download and install it<\/a> on your Windows machine. Follow the default installation steps and don\u2019t forget to keep the option that installs <a href=\"https:\/\/docs.mongodb.com\/compass\/current\/\">MongoDB Compass<\/a> (the default GUI for MongoDB) as well. Once it\u2019s finished, open Compass and create a new database with the Figure 2 configurations.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"673\" height=\"581\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/09\/word-image-238.png\" alt=\"\" class=\"wp-image-81019\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"caption\">Figure 2. Configuring MongoDB new database.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-setting-up-rabbitmq\">Setting up RabbitMQ<\/h2>\n\n\n\n<p>RabbitMQ is going to be the default message broker to the <em>Event<\/em> processing side of the CQRS model. You can pick up another broker that you feel more comfortable with, just be sure to keep the same (similar) configurations. For this, go to the <a href=\"https:\/\/www.rabbitmq.com\/install-windows.html\">installation page<\/a>, and following the instructions to install and sets it up.<\/p>\n\n\n\n<p>Additionally, don\u2019t forget to install the <a href=\"http:\/\/www.erlang.org\/download.html\">Erlang dependency for Windows<\/a>. Once the installer finishes the process, RabbitMQ will be a Windows service that starts up along with your machine, through its default configurations: <em>guest<\/em> as both user and password. To access the administration page, just go to <a href=\"http:\/\/localhost:15672\/\">http:\/\/localhost:15672\/<\/a> in your browser (Figure 3).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1383\" height=\"757\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/09\/word-image-239.png\" alt=\"\" class=\"wp-image-81020\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"caption\">Figure 3. RabbitMQ administration page.<\/p>\n\n\n\n<p>In case this page doesn\u2019t show up the first time, you can force the RabbitMQ Management plugin to restart. For this, go to the RabbitMQ installation <em>\\sbin<\/em> folder and run the following command:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">rabbitmq-plugins.bat enable rabbitmq_management<\/pre>\n\n\n\n<p>Figure 4 goes back step by step. Then, restart your computer and try to access the URL again.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"314\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/09\/word-image-240.png\" alt=\"\" class=\"wp-image-81021\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"caption\">Figure 4. Enabling RabbitMQ Management plugin.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-creating-the-project\">Creating the Project<\/h2>\n\n\n\n<p>Create a new Web Application project by going to <em>File &gt; New &gt; Project<\/em>. Then, select the template <em>ASP.NET Core Web Application<\/em> and name it as <em>CustomerApi<\/em> (Figure 5).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1178\" height=\"816\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/09\/word-image-241.png\" alt=\"\" class=\"wp-image-81022\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"caption\">Figure 5. Creating a new ASP.NET Core Web Application.<\/p>\n\n\n\n<p>You\u2019ll be prompted to select a template for your Web Application, like that shown in Figure 6. Since the application just needs to expose endpoints for the tests, you can select the <em>API<\/em> option and, if you wish to deploy your application on a local Docker container, you can select the <em>Enable Docker Support<\/em>. Remember that this option will require you to have <a href=\"https:\/\/store.docker.com\/editions\/community\/docker-ce-desktop-windows\">Docker previously installed<\/a> on your computer.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"568\" height=\"401\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/09\/word-image-242.png\" alt=\"\" class=\"wp-image-81023\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"caption\">Figure 6. Selecting the application template.<\/p>\n\n\n\n<div class=\"note\">\n<p><em>Note: You can download the completed project from the link at the bottom of the article.<\/em><\/p>\n<\/div>\n\n\n\n<p>Next, you need to add the Entity Framework dependencies to your NuGet dependencies, specifically the one that refers to the SQLite integration. For this, go to menu <em>View &gt; Other Windows &gt; Package Manager Console<\/em> and run the following commands:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">install-package Microsoft.EntityFrameworkCore\ninstall-package Microsoft.EntityFrameworkCore.Sqlite\ninstall-package Microsoft.EntityFrameworkCore.Tools.DotNet<\/pre>\n\n\n\n<p>Then, do the same to the Extensions.Configuration in order to enable the binding of our objects based on predefined key-value pairs; as well as the ASP.NET Core package:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">install-package Microsoft.Extensions.Configuration\ninstall-package Microsoft.Extensions.Configuration.Json\ninstall-package Microsoft.AspNetCore.All<\/pre>\n\n\n\n<p>Next, add the <a href=\"https:\/\/github.com\/mongodb\/mongo-csharp-driver\">MongoDB C# Driver<\/a> dependency to your NuGet dependencies going again to <em>View &gt; Other Windows &gt; Package Manager Console<\/em> and running the following command:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">install-package mongocsharpdriver<\/pre>\n\n\n\n<p>Finally, let\u2019s config the Web API project to have the RabbitMQ Client (once we need it to post and consume messages) installed as a NuGet dependency going once more to the <em>Package Manager Console<\/em> and issuing the command:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">install-package RabbitMQ.Client<\/pre>\n\n\n\n<p>At the end of all these setups, you\u2019ll have the same <em>NuGet Dependencies <\/em>structure as shown in Figure 7.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"471\" height=\"261\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/09\/word-image-243.png\" alt=\"\" class=\"wp-image-81024\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"caption\">Figure 7. Final NuGet Dependencies tree.<\/p>\n\n\n\n<p>Let\u2019s get started with the project configurations letting it know how to interpret the initial launching and app settings. By default, the files <em>launchSettings.json<\/em> (which defines the rules for the IIS server, build, profiling, etc.) and <em>appsettings.json<\/em> (which is responsible for defining the settings in app scope like database connections, amqp, etc.) are created to enable your project configuration customization.<\/p>\n\n\n\n<p>Take a look at the following code listing, starting by the <em>launchSettings.json<\/em> file found in the <em>Properties<\/em> folder. Make a note of the original ports in your file. Change it according to this code and add the original HTTP port back:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n\t\"iisSettings\": {\n\t\t\"windowsAuthentication\": false,\n\t\t\"anonymousAuthentication\": true,\n\t\t\"iisExpress\": {\n\t\t\t\"applicationUrl\": \"http:\/\/localhost:58751\/\",\n\t\t\t\"sslPort\": 0\n\t\t}\n\t},\n\t\"buildOptions\": {\n\t\t\"emitEntryPoint\": true,\n\t\t\"preserveCompilationContext\": true,\n\t\t\"copyToOutput\": {\n\t\t\t\"include\": [ \"appsettings.json\" ]\n\t\t}\n\t},\n\t\"profiles\": {\n\t\t\"IIS Express\": {\n\t\t\t\"commandName\": \"IISExpress\",\n\t\t\t\"launchBrowser\": true,\n\t\t\t\"launchUrl\": \"api\/customers\",\n\t\t\t\"environmentVariables\": {\n\t\t\t\t\"ASPNETCORE_ENVIRONMENT\": \"Development\"\n\t\t\t}\n\t\t},\n\t\t\"CustomerApi\": {\n\t\t\t\"commandName\": \"Project\",\n\t\t\t\"launchBrowser\": true,\n\t\t\t\"launchUrl\": \"api\/customers\",\n\t\t\t\"environmentVariables\": {\n\t\t\t\t\"ASPNETCORE_ENVIRONMENT\": \"Development\"\n\t\t\t},\n\t\t\t\"applicationUrl\": \"http:\/\/localhost:58752\/\"\n\t\t}\n\t}\n}<\/pre>\n\n\n\n<p>Notice too that we have two IIS configurations in the file:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>The first defined in a global IIS server scope, for you to access as a Windows service deployed every time you run the application. This way, it\u2019s not necessary to be in debug mode to access the application;<\/li>\n\n\n\n<li>The second is focused on the development process itself, that is, VS starts the app in a different port in order to allow you to debug the app on that <em>address:port<\/em>.<\/li>\n<\/ul>\n<\/div>\n\n\n<p>The second file, <em>appsettings.json<\/em>, must be changed to the following:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n  \"Logging\": {\n    \"IncludeScopes\": false,\n    \"LogLevel\": {\n      \"Default\": \"Debug\",\n      \"System\": \"Information\",\n      \"Microsoft\": \"Information\"\n    }\n  },\n  \"ConnectionStrings\": {\n    \"DefaultConnection\": \"Filename=.\/customer_db.db\"\n  },\n  \"amqp\": {\n    \"username\": \"guest\",\n    \"password\": \"guest\",\n    \"hostname\": \"localhost\",\n    \"uri\": \"amqp:\/\/localhost:5672\/\",\n    \"virtualhost\": \"\/\"\n  }\n}<\/pre>\n\n\n\n<p>Some configurations are familiar and come within the file when it is created by VS, like the Debug, Console and Logging settings. Here, we\u2019ve added a few others, like:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><em>ConnectionStrings<\/em>: The default connection configuration for your SQLite database (you\u2019ll see how to create the file <em>customer_db.db<\/em> further in the article);<\/li>\n\n\n\n<li><em>amqp<\/em>: Default settings for the RabbitMQ connection. Here, no <em>vhost<\/em> was created to evict greater complexities. The rest are just the default <em>key:values<\/em> pairs of the broker (pay attention to change this to your broker or own properties if they\u2019re not the default ones). Note that the configs, including the port, are the defaults for RabbitMQ. If you have installed it with different properties, so change them here too.<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Plus, once you\u2019re running this example in a local development environment, make sure to copy the same properties to the file <em>appsettings.Development.json<\/em>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-sqlite-integration\">SQLite Integration<\/h2>\n\n\n\n<p>Once all the environment frameworks and tools are configured, let\u2019s move on to the model definitions. We\u2019ll start by creating the C# class of our <em>Repositories<\/em> and <em>Entities<\/em> since these integrations require some work regarding their complexities until we have all of them properly working along with the ASP.NET project.<\/p>\n\n\n\n<p>Before going to the classes creation, you need to create the database file. SQLite was chosen as the CQRS relational database because it is serverless (unlike many other databases, it doesn\u2019t need the common client\/server architecture), that is, it works inside the applications, allowing the reads and writes directly from the file that represents the database itself. It\u2019s perfect for test and quality assurance environments, so we\u2019ll pick it up in order to evict complexity increasing.<\/p>\n\n\n\n<p>So, first, open the <em>DB Browser for SQLite<\/em>, click on <em>New Database<\/em>, navigate to the root folder of the CustomerApi project and save this connection there with the name of <em>customer_db.db<\/em>. Leave the database empty for now.<\/p>\n\n\n\n<p>Get back to the project and create a new project folder called <em>Models<\/em>. Then, another called <em>SQLite <\/em>under<em> Models<\/em>. This is to keep the files of each repository approach separated (since we\u2019re not creating an independent project for each solution). And finally, create three new files called <em>CustomerRecord.cs, PhoneRecord.cs <\/em>and<em> PhoneType.cs<\/em>. They must have the following contents:<\/p>\n\n\n\n<p><strong>CustomerRecord.cs<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using System.Collections.Generic;\nnamespace CustomerApi.Models.SQLite\n{\n\tpublic class CustomerRecord\n    {\n\t\tpublic long Id { get; set; }\n\t\tpublic string Email { get; set; }\n\t\tpublic string Name { get; set; }\n\t\tpublic int Age { get; set; }\n\t\tpublic List&lt;PhoneRecord&gt; Phones { get; set; }\n\t}\n}<\/pre>\n\n\n\n<p><strong>PhoneRecord.cs<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">namespace CustomerApi.Models.SQLite\n{\n\tpublic class PhoneRecord\n    {\n\t\tpublic long Id { get; set; }\n\t\tpublic PhoneType Type { get; set; }\n\t\tpublic int AreaCode { get; set; }\n\t\tpublic int Number { get; set; }\n\t}\n}<\/pre>\n\n\n\n<p><strong>PhoneType.cs<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">namespace CustomerApi.Models.SQLite\n{\n\tpublic enum PhoneType\n\t{\n\t\t\tHOMEPHONE, CELLPHONE, WORKPHONE\n\t}\n}<\/pre>\n\n\n\n<p>The structure is lean: some simple attributes and a list phones represented by the second record entity. This one, specifically, needs to have the back-relation to the customer defined in order for the Entity Framework migration feature be able to understand and create the proper relationship between them.<\/p>\n\n\n\n<p>The <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/jj591621(v=vs.113).aspx\">Entity Framework First Migration<\/a> is a feature that allows you to migrate the structure of your Entities models to the original database. Once you\u2019ve defined the model classes, Entity Framework will be able, through this feature, to read the entities structure metadata and execute the corresponding scripts to create the tables, columns, etc. in the final datastore.<\/p>\n\n\n\n<p>To use this, go to the project root folder and edit the file <em>CustomerApi.csproj<\/em>. Search for the tag <code>&lt;ItemGroup&gt;<\/code> and add the following item to it:<\/p>\n\n\n\n<p>&lt;DotNetCliToolReference Include=&#8221;Microsoft.EntityFrameworkCore.Tools.DotNet&#8221; Version=&#8221;2.0.2&#8243; \/&gt;<\/p>\n\n\n\n<p>Restart your IDE. Now, you need to create the database context that\u2019ll command the rules of the migration. In the <em>Models\/SQLite<\/em> folder, create a new class and name it as <em>CustomerSQLiteDatabaseContext.cs<\/em>. Add the following content:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using Microsoft.EntityFrameworkCore;\nnamespace CustomerApi.Models.SQLite\n{\n\tpublic class CustomerSQLiteDatabaseContext : DbContext\n\t{\n\t\tpublic CustomerSQLiteDatabaseContext(DbContextOptions&lt;CustomerSQLiteDatabaseContext&gt; options)\n\t\t\t: base(options)\n\t\t{\n\t\t}\n\t\tprotected override void OnModelCreating(ModelBuilder modelBuilder)\n\t\t{\n\t\t\tmodelBuilder.Entity&lt;CustomerRecord&gt;()\n\t\t\t\t\t\t.HasMany(x =&gt; x.Phones);\n\t\t}\n\t\tpublic DbSet&lt;CustomerRecord&gt; Customers { get; set; }\n\t}\n}<\/pre>\n\n\n\n<p>It basically defines the model builder and how it is going to consider the customer -&gt; phones relation when generating the database structures. Here, it\u2019s important to correctly set up the <em>one<\/em> and <em>many<\/em> sides of the entity relationships, as well as the foreign keys.<\/p>\n\n\n\n<p>Then, go again to the <em>Models\/SQLite<\/em> folder and create the repository class, called <em>CustomerSQLiteRepository.cs<\/em>. This one will be responsible for holding the context object and managing the operations of the SQLite database file:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using System.Collections.Generic;\nusing System.Linq;\nnamespace CustomerApi.Models.SQLite\n{\n\tpublic class CustomerSQLiteRepository\n\t{\n\t\tprivate readonly CustomerSQLiteDatabaseContext _context;\n\t\tpublic CustomerSQLiteRepository(CustomerSQLiteDatabaseContext context)\n\t\t{\n\t\t\t_context = context;\n\t\t}\n\t\tpublic CustomerRecord Create(CustomerRecord customer)\n\t\t{\n\t\t\tMicrosoft.EntityFrameworkCore.ChangeTracking.EntityEntry&lt;CustomerRecord&gt; entry = _context.Customers.Add(customer);\n\t\t\t_context.SaveChanges();\n\t\t\treturn entry.Entity;\n\t\t}\n\t\tpublic void Update(CustomerRecord customer)\n\t\t{\n\t\t\t_context.SaveChanges();\n\t\t}\n\t\tpublic void Remove(long id)\n\t\t{\n\t\t\t_context.Customers.Remove(GetById(id));\n\t\t\t_context.SaveChanges();\n\t\t}\n\t       public IQueryable&lt;CustomerRecord&gt; GetAll()\n\t       {\n                     return _context.Customers;\n              }\n\t\tpublic CustomerRecord GetById(long id)\n\t\t{\n\t\t\treturn _context.Customers.Find(id);\n\t\t}\n\t}\n}<\/pre>\n\n\n\n<p>Note that the methods are common CRUD operations performed onto the <em>Customers<\/em> object of the context.<\/p>\n\n\n\n<p>Finally, you must adjust the <em>Startup.cs<\/em> file of the project to understand the new configs, by adding a new <em>DBContext <\/em>as well as a repository transient to the <code>ConfigureServices<\/code> method:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">services.AddDbContext&lt;CustomerSQLiteDatabaseContext&gt;(options =&gt;\t\toptions.UseSqlite(Configuration.GetConnectionString(\"DefaultConnection\")));\nservices.AddTransient&lt;CustomerSQLiteRepository&gt;();<\/pre>\n\n\n\n<p>Don\u2019t forget the proper using statements in the beginning of the file:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using CustomerApi.Models.SQLite;\nusing Microsoft.EntityFrameworkCore;<\/pre>\n\n\n\n<p>To guarantee that the database is in fact created, you can also add the following code to the <code>Configure<\/code> method:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using (var serviceScope = app.ApplicationServices.GetService&lt;IServiceScopeFactory&gt;().CreateScope())\n\t\t\t{\n\tvar context = serviceScope.ServiceProvider.GetRequiredService&lt;CustomerSQLiteDatabaseContext&gt;();\n\tcontext.Database.EnsureCreated();\n}<\/pre>\n\n\n\n<p>Now, let\u2019s test the migrations feature. Open the command prompt, navigate to the project root folder and issue the following commands:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">dotnet ef migrations add CreateDatabase\ndotnet ef database update<\/pre>\n\n\n\n<p>The first command will build the project, read the entity models and create the migration files to migrate the model. The second command triggers the commands to be executed directly into the database.<\/p>\n\n\n\n<p>After that, open the DB Browser again<em> for SQLite<\/em> and observe the tables generated automatically.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-first-hints-with-the-api\">First Hints with the API<\/h2>\n\n\n\n<p>To give you a taste of how this API must operate the command side of the CQRS application, let\u2019s create the controller facade for the API to handle basic CRUD operations.<\/p>\n\n\n\n<p>For this, in the <em>\/Controllers<\/em> folder, rename the default generated controller class to <em>CustomersController.cs<\/em> and change its content to the following:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using CustomerApi.Models.SQLite;\nusing Microsoft.AspNetCore.Mvc;\nnamespace CustomerApi.Controllers\n{\n    [Route(\"api\/[controller]\")]\n\tpublic class CustomersController : Controller\n\t{\n\t\tprivate readonly CustomerSQLiteRepository _sqliteRepository;\n        \tpublic CustomersController(CustomerSQLiteRepository sqliteRepository)\n\t\t{\n\t\t\t_sqliteRepository = sqliteRepository;\n\t\t}\n\t\t[HttpGet]\n\t\tpublic IActionResult GetAll()\n\t\t{\n\t\t   var customers = _sqliteRepository.GetAll();\n\t\t   if (customers == null)\n\t\t   {\n           \t\treturn NotFound();\n            \t   }\n\t\t   return new ObjectResult(customers);\n\t\t}\n\t\t[HttpGet(\"{id}\", Name = \"GetCustomer\")]\n\t\tpublic IActionResult GetById(long id)\n\t\t{\n\t\t\tvar customer = _sqliteRepository.GetById(id);\n\t\t\tif (customer == null)\n\t\t\t{\n\t\t\t\treturn NotFound();\n\t\t\t}\n\t\t\treturn new ObjectResult(customer);\n\t\t}\n\t\t[HttpPost]\n\t\tpublic IActionResult Post([FromBody] CustomerRecord customer)\n\t\t{\n            CustomerRecord created = _sqliteRepository.Create(customer);\n\t\t\treturn CreatedAtRoute(\"GetCustomer\", new { id = created.Id }, created);\n\t\t}\n\t\t[HttpPut(\"{id}\")]\n\t\tpublic IActionResult Put(long id, [FromBody] CustomerRecord customer)\n\t\t{\n\t\t\tvar record = _sqliteRepository.GetById(id);\n\t\t\tif (record == null)\n\t\t\t{\n\t\t\t\treturn NotFound();\n\t\t\t}\n\t\t\tcustomer.Id = id;\n            _sqliteRepository.Update(customer);\n\t\t\treturn NoContent();\n\t\t}\n\t\t[HttpDelete(\"{id}\")]\n\t\tpublic IActionResult Delete(long id)\n\t\t{\n\t\t\tvar record = _sqliteRepository.GetById(id);\n\t\t\tif (record == null)\n\t\t\t{\n\t\t\t\treturn NotFound();\n\t\t\t}\n            _sqliteRepository.Remove(id);\n\t\t\treturn NoContent();\n\t\t}\n\t}\n}<\/pre>\n\n\n\n<p>Notice that the same endpoints (each HTTP method) are created based on the <a href=\"https:\/\/restfulapi.net\/\">RESTful principles<\/a> to facilitate the pattern and make it more understandable for the clients to integrate.<\/p>\n\n\n\n<p>Now, you can test each endpoint and check the data being saved to the SQLite database, as well as being queried from there when it comes to the GET operation. You can use <a href=\"https:\/\/www.getpostman.com\/\">Postman<\/a>, or any other REST-like testing tool of your preference, to test the calls to the API. For example, let\u2019s create a new customer just like shown in <strong>Figure 8<\/strong>. Make sure to modify the port. Here is the JSON code you will need to create the customer:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n\t\t\"phones\": [\n\t\t\t{\n\t\t\t\t\t\"type\":0,\n\t\t\t\t\t\"areacode\":321,\n\t\t\t\t\t\"number\": 0003010\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t],\n\t\t\t\"email\":\"georgi@michales.com\",\n\t\t\t\"name\": \"Georgia Michales\",\n\t\t\t\"age\": 12\n}<\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"757\" height=\"885\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/09\/word-image-244.png\" alt=\"\" class=\"wp-image-81025\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"caption\">Figure 8. Testing the customer\u2019s creation with Postman.<\/p>\n\n\n\n<p>Now, go and check the database where you should see the new record added to the table. Also, call the GET (and the other HTTP verbs) operation with this URL to see if the result is coming correctly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-conclusion\">Conclusion<\/h2>\n\n\n\n<p>This will give you that notion of CRUD that most developers are used to when it comes to application development. In fact, that sense is part of the CQRS nature, which means that one thing doesn\u2019t need to live without the other. Actually, they refer to each other in a way that are complementary operations.<\/p>\n\n\n\n<p>In the next part of this series, we\u2019ll dive into event processing, the NoSQL side of the querying model and how everything can work together.<\/p>\n\n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>FAQs: Getting Started with CQRS \u2013 Part 1<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. What is CQRS and why use it in ASP.NET Core?<\/h3>\n            <div class=\"faq-answer\">\n                <p>CQRS (Command Query Responsibility Segregation) is an architectural pattern where the read operations (queries) and write operations (commands) of an application use separate models and potentially separate datastores. Queries return data without side effects; commands modify state and may return only a success\/failure result. Benefits: queries can be optimised for read performance independently of write performance; complex domain logic for writes is separated from the read projection logic; the write side can use eventual consistency through event messaging, allowing independent scaling. In ASP.NET Core, CQRS integrates well with MediatR, message brokers (RabbitMQ, Azure Service Bus), and separate read\/write databases.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. What is the difference between CQRS and CRUD?<\/h3>\n            <div class=\"faq-answer\">\n                <p>CRUD (Create, Read, Update, Delete) uses a single model and a single datastore for both reading and writing. It is simple, appropriate for most standard web applications, and should be the default. CQRS introduces complexity and should only be used when: the read and write workloads are fundamentally different in scale or structure (e.g., one write triggers multiple read projections); you need eventual consistency between write and read models; or the domain is complex enough to benefit from separate models for command and query logic. Don&#8217;t apply CQRS to simple data access scenarios &#8211; CRUD is almost always the right choice for standard web APIs.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. What role does RabbitMQ play in a CQRS architecture?<\/h3>\n            <div class=\"faq-answer\">\n                <p>In CQRS with event sourcing, write-side commands produce events (facts about what happened). A message broker like RabbitMQ decouples the command handler (which records the event) from the event handlers (which update read models, send notifications, trigger other processes). When a command is processed, the handler publishes an event to a RabbitMQ queue. Separate event handlers subscribe to the queue and update the MongoDB read model, send emails, or trigger downstream processes. This decoupling means the command side doesn&#8217;t need to know what happens downstream &#8211; and different handlers can be scaled or updated independently.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">4. What is the MediatR library and how does it relate to CQRS in .NET?<\/h3>\n            <div class=\"faq-answer\">\n                <p>MediatR is a .NET library that implements the mediator pattern &#8211; dispatching requests (commands and queries) to their corresponding handlers. In a CQRS implementation, MediatR provides the dispatch infrastructure: you define a command class, a query class, and their respective handlers; MediatR routes them at runtime without the command issuer needing to reference the handler directly. MediatR is widely used in .NET CQRS implementations as a clean alternative to direct service calls or explicit message bus routing for in-process communication.<\/p>\n            <\/div>\n            <\/section>\n","protected":false},"excerpt":{"rendered":"<p>Implement CQRS in ASP.NET Core using MongoDB for the query side, RabbitMQ as the message broker for events, and SQLite for the command side. Part 1 covers environment setup, project creation, and the first API endpoints.&hellip;<\/p>\n","protected":false},"author":320401,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":true,"footnotes":""},"categories":[143538,53],"tags":[],"coauthors":[60461],"class_list":["post-81017","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","category-featured"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/81017","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/320401"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=81017"}],"version-history":[{"count":12,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/81017\/revisions"}],"predecessor-version":[{"id":109802,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/81017\/revisions\/109802"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=81017"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=81017"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=81017"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=81017"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}