Command/Query library with network and IoC support

Have you read about the Command/Query separation pattern and wondered how hard it would be to get started with it? With Griffin framework you only need a few lines of code to have everything configured, no matter if the messages are being executed in process or executed in a server application somewhere.

If you’ve followed my blog you have probably seen my Griffin.Decoupled library which was my first attempt to create something similar to a CQS library. It became however complex quick as I manage to squeeze in too many features at the same time. This time I’ve taken another approach. Less but good features. I’ve even separated the contracts from the implementation so that others can implement the same interfaces without having to have a hard dependency on Griffin framework.

That means that you do not have to change your code base if you are doing CQS using ASP.NET, NServiceBus, Azure or my library. The only difference is that you need to configure different implementations during application startup.

The specification

The specification library is called DotNetCqs and is lightweight (7kb). It’s really easy to use. To define a command inherit the Command class, and to execute a command implement the ICommandHandler<TCommand> interface. The same logic applies for queries, application events and request/replies.

Here is a sample request/reply:

public class Login : Request<LoginReply>
{
    public Login(string userName, string password)
    {
        Password = password;
        UserName = userName;
    }

    public string UserName { get; private set; }
    public string Password { get; private set; }
}

public class LoginReply
{
    public bool Success { get; set; }
    public Account Account { get; set; }
}

To trigger the CQS messages you execute them through BUS classes. To invoke the request above you run the following code:

var reply = await requestBus.ExecuteAsync(new Login("jonas", "arne"));
if (reply.Success)
{
    Console.WriteLine("Authenticated as " + reply.Account.UserName);
}

That’s dead easy.

Simplicity delivered

One goal with the library was to make it as small as possible so that implementors do not have to struggle. The request bus is for instance defined like this:

public interface IRequestReplyBus
{
    Task<TReply> ExecuteAsync<TReply>(Request<TReply> request);
}

The coolness

As the contracts (i.e. the interfaces) are so lightweight it allows us to do easy combinations. You could for instance use the decorator pattern to create a bus that uses load balancing, temporary storage and networking:

var bus = new TransactionalBus(
              new LoadBalancedBus(
                  new NetworkBus("192.168.1.20:3040"), 
                  new NetworkBus("192.168.1.21:3040"), 
                  new NetworkBus("192.168.1.22:3040")
              )
          );

That’s 100% transparent for the user once configured. All they know is that they use a simple interface with one method.

Download

The package can be installed using nuget:

install-package dotnetcqs

The code is available at github under the Apache license.

Griffin Framework implementation

Griffin Framework contains three different implementations that you can choose from.

The simple

The first implementation uses reflection to find all CQS handlers. It index them and create a new handler each time a message is being executed.

Sample setup

// setup
var bus = new SimpleCommandBus();
bus.Register(Assembly.GetExecutingAssembly());

//execute
await bus.ExecuteAsync(new IncreaseSalary(19549, 50000));

GitHub contains more documentation.

Inversion of control

I’ve also created bus implementations which can utilize your favorite container (all that is required is implementation of two simple interfaces). I’ve added support for Autofac (install nuget package griffin.framework.autofac) and Unity (install nuget package griffin.framework.unity).

Read for instance the CQS documentation for Autofac too see how you configure it.

Network

Finally I’ve created a dead easy server in Griffin Framework which supports pipelining, secure transport, authentication etc etc. It’s called SimpleServer. I’ve used it as a base to create a CQS server and a client to accompany it.

The server itself can take different shapes depending on how you configure it. It can for instance run as a HTTP server or use our built in transport protocol MicroMsg. The default implementation uses MicroMsg as transport and DataContractSerializer to serialize the CQS messages.

At client side register CqsClient as ICommandBus, IQueryBus, IEventBus and IRequestReplyBus in your favorite container (or use it directly).

Sample setup:

class ClientDemo
{
    private CqsClient _client;

    public ClientDemo()
    {
        _client = new CqsClient(() => new JsonMessageSerializer());
    }

    public async Task RunAsync(int port)
    {
        await _client.StartAsync(IPAddress.Loopback, port);

        var response = await _client.ExecuteAsync<LoginReply>(new Login("jonas", "mamma"));
        if (response.Success)
            Console.WriteLine("Client: Logged in successfully");
        else
        {
            Console.WriteLine("Client: Failed to login");
            return;
        }

        await _client.ExecuteAsync(new IncreaseDiscount(20));


        var discounts = await _client.QueryAsync(new GetDiscounts());
        Console.WriteLine("Client: First discount: " + discounts[0].Name);
    }
}

The server is configured like this:

public class ServerDemo
{
    private LiteServer _server;

    public int LocalPort
    {
        get { return _server.LocalPort; }
    }

    public void Setup()
    {
        var root = new CompositionRoot();
        root.Build();

        var module = new CqsModule
        {
            CommandBus = CqsBus.CmdBus,
            QueryBus = CqsBus.QueryBus,
            RequestReplyBus = CqsBus.RequestReplyBus,
            EventBus = CqsBus.EventBus
        };


        var config = new LiteServerConfiguration();
        config.DecoderFactory = () => new MicroMessageDecoder(new JsonMessageSerializer());
        config.EncoderFactory = () => new MicroMessageEncoder(new JsonMessageSerializer());

        config.Modules.AddAuthentication(new AuthenticationModule());
        config.Modules.AddHandler(module);

        _server = new LiteServer(config);
    }

    public void Start()
    {
        _server.Start(IPAddress.Any, 0);
    }
}

This implementation will also transport all exceptions from the server back to the client automatically. That makes the client/server implementation transparent (if you ignore the network latency) to the caller.

Sample project

Browse or run our sample project.

  • V

    whats the difference between the command vs request/reply vs query? I can see that command doesnt have a return but is there any example in your repo to illustrate different usage?