Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Validation within Aggregate Roots - Part 2
public interface IValidationHandler<in T> where T : Command {
bool Validate(T cmd);
public interface ICommandValidator {
bool Validate<T>(T command) where T : Command;
// Allows for all command validators to be registered on app start
public class CommandValidator : ICommandValidator {
private readonly IDictionary<Type, Func<object, bool>> _validationHandlers = new Dictionary<Type, Func<object, bool>>();
public void RegisterValidator<T>(Func<T,bool> handler) where T : Command {
_validationHandlers.Add(typeof(T), o => handler((T) o));
public bool Validate<T>(T command) where T : Command {
Func<object, bool> handler;
return !_validationHandlers.TryGetValue(command.GetType(), out handler) || handler(command);
// Class to encapsulate all command validation rules for an Aggregate Root
public class PatientValidationHandler : IValidationHandler<AddReferredPatient>, IValidationHandler<ChangePatientAddress> {
public bool Validate(AddReferredPatient command) {
if (string.IsNullOrWhitespace(command.Firstname))
throw new CommandValidationException("firstname", "First Name is required");
// Register your command validators as you might your command handlers (N.B. this could be done with an IoC or reflection to auto-wireup)
var patientValidator = new PatientValidationHandler();
// Then on all command sending
protected void Send<T>(T cmd) where T : Command {
try {
if (Validator.Validate(cmd)) {
catch (ValidationException ex) {
// This catches both Command Validation exception and Domain validation exceptions (which both inherit from ValidationException)
// manage your feedback to the UI as you see fit but I've gone with the below.
foreach(var error in ex.Errors) {
ModelState.AddModelError(error.ParamName, error.Message);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.