Introducing Command Query Responsibility Separation (CQRS)
page 4 of 5
by Steven Smith
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 30851/ 120

Implementation

The easiest way I've found to get started implementing a CQRS system is to download the community edition of NServiceBus and run through some of the samples.  NServiceBus is a mature open-source application designed to minimize the amount of work needed to get started with using messaging within your applications.  There is a significant learning curve involved with NServiceBus, but it's one of the easiest ways to get started.

As I write this, NServiceBus' latest version is 2.5, and there are both community and commercial versions available.

The following diagram, from NServiceBus' architectural principles, demonstrates how Commands and Queries may be separated within the application's architecture into two separate pipelines.

When implementing CQRS using NServiceBus, consider creating a local data store on your web server (for instance, using SQL Server Express) which only includes the data needed to be displayed currently.  This data may be in a completely different format than your production database, and will often be denormalized and pre-computed so that reports and summaries can be displayed extremely quickly.

Once this data store is in place, the next step is to ensure it is periodically updated.  You can do this on some kind of a scheduled basis, and depending on your application's needs this might be as simple as removing the node from the load balancer, wiping out the database, and running a fresh population script from the canonical data store.  More typically, updates to the local read-only stores can be done by using a Publisher-Subscriber messaging model, in which the main data store publishes updates that are of interest to the read-only stores, and each read-only store subscribes to these messages and responds to them by updating the data in question.  Typically the messages sent in this scenario do not contain the data updates themselves, but rather act as a notification to the subscriber that it needs to update its data.

The web application can continue to use SQL (assuming that's what it used before) to access its read-only data, with the only difference being the location of the data store and perhaps the schema of the tables involved (which should more closely map to the individual pages in the application).

With a local data store in place and a Pub-Sub mechanism in place to ensure these are kept up-to-date, the system will already be much more scalable, as the read load on the primary data store will be greatly reduced.  The second part of the equation (which of course can be implemented first or instead of the local data store) is to remove direct writes between the application and the canonical data store.

Rather than issuing INSERT or UPDATE or DELETE commands to the data store, these commands are encapsulated into messages which are written to a local, transactional queue.  These queued messages are picked up by a handler that is responsible for applying them to the data store, as well as handling any issues that may occur (including retrying the operation or handling exceptions).  From the web application's point of view, rather than calling a method to perform the command, which in turn executes some SQL or calls a stored procedure, a message is created and sent.  This might look something like this:

            var message = new OrderMessage(
                customerId,
                orderItems,
                shippingDetails,
                paymentDetails);
 
            var bus = IoC.Resolve<IBus>();
            bus.Send(message);

 

The configuration required to get started with NServiceBus is pretty minimal as well.  For message processing, the Generic Host application provides an good starting point and can be installed as a service, with built-in profiles for dev/integration/production settings in terms of logging and persistence.  For the web application, something like the following needs to run prior to the first message being sent:

            Configure.WithWeb()
                .StructureMapBuilder((IContainer) container)
                .Log4Net()
                .XmlSerializer()
                .MsmqTransport().IsTransactional(true)
                .UnicastBus()
                .LoadMessageHandlers()
                .CreateBus()
                .Start();

 

And a little bit of configuration needs to be added to web.config:

<configuration>
  <configSections>   
        <section name="MsmqTransportConfig" 
            type="NServiceBus.Config.MsmqTransportConfig, NServiceBus.Core" />
    <section name="UnicastBusConfig" 
            type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
    <section name="Logging" type="NServiceBus.Config.Logging, NServiceBus.Core"/>
</configSections>
...
  <MsmqTransportConfig InputQueue="webinputqueue" ErrorQueue="error"
    NumberOfWorkerThreads="1"
    MaxRetries="5"
  />
 
  <UnicastBusConfig
    DistributorControlAddress=""
    DistributorDataAddress="">
    <MessageEndpointMappings>
      <add Messages="Application.Infrastructure" Endpoint="mainqueue" />
    </MessageEndpointMappings>
  </UnicastBusConfig>
 
  <Logging Threshold="WARN" />

 

This is just an example, and is meant to show how little code is required to get started with sending messages from your web application and handling them from an NServiceBus Host application/service.

 


View Entire Article

User Comments

No comments posted yet.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2018 ASPAlliance.com  |  Page Processed at 2018-10-19 4:37:32 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search