Command and Query-based Entity Framework architecture PART 2

In my previous post I described a different take on an Entity Framework architecture with commands and queries. I probably confused the ones that know every angle of CQRS since my commands contained more than just holding new state. However, the intention was not to do a CQRS solution. It is only meant to be an alternative to repositories with the concept of “one business rule equals one command or query” in mind.

PSST! The code can be found here: https://github.com/tobiasnilsson/CommandQuerySample/.
PSST2! Sorry for the badly formatted code. I will try to find a better way to paste code from Visual Studio into WordPress…

PSST3! I refer to the different projects in the solutio in the following text. Core contains the definition of the application. Infrastructure provides the implementation. See prev post for details.

The command classes are responsible for three things:

  • Validating data,
  • handle the state and
  • persist the state in the database

Like this:

public class AddUserToDepartmentsCommand : CommandBase, IAddUserToDepartmentsCommand
{
public AddUserToDepartmentsCommand(ISampleDbContext context) : base(context)
{
}
 
public void Add(User user, IEnumerable<Department> departments)
{
if(user == null)
throw new ArgumentNullException("user");

 

if(departments == null)
throw new ArgumentNullException("departments");

 

if(!departments.Any())
throw new ArgumentException("departments");

 
foreach (var department in departments)
{
department.Users.Add(user);
}
 
Context.SaveChanges();
}
}

So refactoring the command concept seem to be a good idea! I will borrow some of the concepts from CQRS when doing this refactoring, such as command and command handler. Commands will now only hold state, i.e. become POCO classes.

 

First step: add class to hold new state

A class called NewAddUserToDepartmentsCommand is added to the Core project. It looks like this:

public class NewAddUserToDepartmentsCommand : ICommand
{
public User User { get; set; }
public IEnumerable<Department> Departments { get; set; }
}

Also, the empty interface ICommand is added to the Core project. This interface only acts as a marker for commands.

public interface ICommand
{
}

Second step: add command handling

A class called NewAddUserToDepartmentsCommandHandler is added to the Infrastructure project since this will be specific to the implementation of the persistence stuff (in this case an Entity Framework based persistence). The handler will act on the data and add it to the EF context.

public class NewAddUserToDepartmentsCommandHandler : ICommandHandler<NewAddUserToDepartmentsCommand>
{
private readonly ISampleDbContext _context;
 
public NewAddUserToDepartmentsCommandHandler(ISampleDbContext context)
{
_context = context;
}
 
public void Handle(NewAddUserToDepartmentsCommand command)
{
foreach (var department in command.Departments)
{
department.Users.Add(command.User);
}
}
}

 

Also, the generic interface ICommandHandler is added to the Core project. This provides two features: it defines the Handle method and provides a relationship between the Command class and the corresponding CommandHandler.

public interface ICommandHandler<in TCommand> where TCommand : ICommand
{
void Handle(TCommand command);
}

 

Third step: add command persistence

A class called CommandExecutor is added to the Infrastructure project. This class receives the commands that should be handled and persisted in the database through Entity Framework.

Side note: in many cases you want to persist data in a transaction. If one of the commands fails to execute or persist data, the other commands should not persist data either. In the previous solution, each command was responsible for persistence (each command called Context.SaveChanges()).

public class CommandExecutor : ICommandExecutor
{
private readonly ISampleDbContext _context;
private readonly ICommandDispatcher _dispatcher;
 
public CommandExecutor(ISampleDbContext context, ICommandDispatcher dispatcher)
{
_context = context;
_dispatcher = dispatcher;
}

 

public void Execute(IEnumerable<ICommand> commands)
{
foreach (var command in commands)
{
 
var validator = _dispatcher.GetValidator(command);
var validationResult = validator.Validate(command);
 
if (!validationResult.IsValid)
throw new CommandValidationException(validationResult.ErrorMessages);
 
var handler = _dispatcher.GetHandler(command);
handler.Handle(command);
}
 
_context.SaveChanges();
}
}

 

However, when calling SaveChanges on the context in this case nothing should happen I guess. No data is persisted. The context used in this CommandExecutor is a different instance the instance used in each of the CommandHandlers. The context is injected in the constructors of the commands and the executor. Calling SaveChanges in the executor class will act on a different context than in the commands. Structuremap to the rescue!

Since the running application is a web application, we can specify that ONE instance of SampleDbContext should be used throughout the web request:

public static class IoC {
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.AssembliesFromApplicationBaseDirectory();
scan.WithDefaultConventions();
 

//Add the assemblies that contains the handlers and validators to the scanning
scan.AssemblyContainingType<NewAddUserCommandHandler>();
scan.IncludeNamespaceContainingType<NewAddUserCommandHandler>();
scan.AssemblyContainingType<NewAddUserCommandValidator>();
scan.IncludeNamespaceContainingType<NewAddUserCommandValidator>();
 

//Register all types of command validators and handlers
scan.AddAllTypesOf(typeof(ICommandHandler<>));
scan.AddAllTypesOf(typeof(ICommandValidator<>));
 
});

 

//The context needs to be one instance per http request
x.For<ISampleDbContext>().HttpContextScoped().Use<SampleDbContext>();
});

return ObjectFactory.Container;
}
}

 

Ok, back to the executor. The command executor implements the following interface located in the Core project:

public interface ICommandExecutor
{
void Execute(IEnumerable<ICommand> commands);
}

 

Step four: get command handler for a command

A class named CommandDispatcher is added to the Infrastructure project. This class provides a way of matching a command with its handler and validator objects. This is where the magic happens! The command is passed to each of the methods GetHandler and GetValidator. They both return the corresponding commandhandler and commandvalidator.

 

public class CommandDispatcher : ICommandDispatcher
{
public ICommandHandler GetHandler(ICommand command)
{
var commandType = command.GetType();
 
Type handlerType = typeof(ICommandHandler<>);
Type constructedClass = handlerType.MakeGenericType(commandType);
 
var handler = ObjectFactory.GetInstance(constructedClass);
 
return handler as ICommandHandler;
}
 
public ICommandValidator GetValidator(ICommand command)
{
var commandType = command.GetType();
 
Type validatorType = typeof(ICommandValidator<>);
Type constructedClass = validatorType.MakeGenericType(commandType);
 
var validator = ObjectFactory.GetInstance(constructedClass);
 
return validator as ICommandValidator;
}
}

 

…and the ICommandDispatcher interface in the Core project:

public interface ICommandDispatcher
{
ICommandHandler GetHandler(ICommand command);
ICommandValidator GetValidator(ICommand command);
}

 

The matching between a command and its handler can be done since each command implements the generic interface ICommandHandler<T> which in turn depends upon the non-generic interface ICommandHandler:

 

public interface ICommandHandler
{
void Handle(object commandObj);
}
 

public interface ICommandHandler<TCommand> : ICommandHandler where TCommand : ICommand
{
}

 

 

Step five: break out validation

The original command contained some ”validation” of the data before acting on it and adding it to the context.

if(user == null)
throw new ArgumentNullException("user");
 
if(departments == null)
throw new ArgumentNullException("departments");
 
if(!departments.Any())
throw new ArgumentException("departments");

 

The validation will now take place in a new class:

public class NewAddUserToDepartmentsValidator : ICommandValidator<NewAddUserToDepartmentsCommand>
{
public ValidationResult Validate(NewAddUserToDepartmentsCommand command)
{
var result = new ValidationResult();
 
if (command.User == null)
{
result.IsValid = false;
result.ErrorMessages.Add("Must contain user");
}

 

if (command.Departments == null || !command.Departments.Any())
{
result.IsValid = false;
result.ErrorMessages.Add("Must contain departments");
}
 
return result;
}
}

The validation messages are meant to be user friendly and could be passed to the user interface or some error log if validation fails. Although, this is not a replacement for the model validation that should take place in the UI or MVC controller action prior to creating the command and passing it to the CommandExecutor.

The validation class implements the following interface:

public interface ICommandValidator<in TCommand> where TCommand : ICommand
{
ValidationResult Validate(TCommand command);
}

 

…and ValidationResult:

public class ValidationResult
{
public bool IsValid { get; set; }
public IList<string> ErrorMessages { get; set; }
}

 

The idea of the generic interface ICommandValidator is to be able to define the relationship between the validator and the command itself. In the same way as between command handlers and commands.

 

The validation takes place inside the CommandExecutor like this:

public class CommandExecutor : ICommandExecutor
{
private readonly ISampleDbContext _context;
private readonly ICommandDispatcher _dispatcher;
 
public CommandExecutor(ISampleDbContext context, ICommandDispatcher dispatcher)
{
_context = context;
_dispatcher = dispatcher;
}
 
public void Execute(IEnumerable<ICommand> commands)
{
foreach (var command in commands)
{
var commandType = command.GetType();
 
var validator = _dispatcher.GetValidator(commandType);
                var validationResult = validator.Validate(command);

 

                if (!validationResult.IsValid)

                    throw new CommandValidationException(validationResult.ErrorMessages);

 

var handler = _dispatcher.GetHandler(commandType);

handler.Handle(command);

}

 

_context.SaveChanges();

}

}

 

In lack of a better solution, I use the command dispatcher to load the correct validator given the command.

 

This is a work in progress. Most likely there will be more refactoring done in the near future.

6 thoughts on “Command and Query-based Entity Framework architecture PART 2

  1. Nice writeup 🙂 I especially like the separation between the command handling logic and its validation.

    One observation: I noticed that the CommandDispatcher obtains an instance of a command handler by actively requesting it from an IoC container.
    What if you inverted that dependency and let the container subscribe a command handler to the CommandDispatcher when it is resolved? The CommandDispatcher would then have a list of command handlers associated to the different commands and simply return them to the CommandExecutor.

    /Enrico

  2. Nice article. It is that I just looked for. Thanks. Would you please describe (provably add) event sourcing with this architecture?

  3. Great article, but in contrary to Mojam’s request, PLEASE DONT add event sourcing! It is hard to find decent clear CQRS implementations on the web (that are ideal for someone beginning the CQRS journey) that aren’t cluttered with ES muddying the water.

    If you do add event sourcing into an example please branch it and leave the original clear!

  4. Pingback: Casting to correct type after using Activator.CreateInstance | Solutions for enthusiast and professional programmers

  5. This is a good article an I know its older but I think a better solution would be is to add a decorator to your ICommandHandlers. You’re using the dispatcher as a service locator, Instead decorate the ICommandHandler with CommandValidator, CommandLogger, etc classes.
    An IoC container makes this pretty easy to set up.You only need 2 interfaces. ICommand and ICommandHandler where TCommand : ICommand

Leave a comment