I want to introduce a simple command handler pattern in order to separate commands and queries of your applications if it’s needed. Sometimes especially in large-scale applications, you need to have two layers for reading and write separated and assign two teams to work on them.
You can use the pattern in this post based on the complexity and needs of your application. I recommend that don’t call this CQRS pattern as it’s something completely different and more complex.
Get started and Create an interface with no any member:
1 2 3 4 5 | public interface ICommand { } |
You will see later in this blog post that ICommand is just a flag to determine the commands for the handler. Every command which is trying to make a change in application’s state should return a result. so create another interface named ICommandResult
1 2 3 4 5 6 7 8 9 | public interface ICommandResult { string Message { get ; } bool Success { get ; } } |
implement the above interface as CommandResult and derive the FailureResult and SuccessResult classes from:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | internal abstract class CommandResult : ICommandResult { public string Message { get ; protected set ; } public bool Success { get ; protected set ; } } internal class FailureResult : CommandResult { public FailureResult( string message) { Success = false ; Message = message; } } internal class SuccessResult : CommandResult { public SuccessResult( string message) { Success = true ; Message = message; } } |
Now create an interface for handling the validations in CommandBus class:
1 2 3 4 5 6 7 | internal interface IValidationHandler< in TCommand> where TCommand : ICommand { IEnumerable<ValidationResult> Validate(TCommand command); } |
And create a class for validations:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | public class ValidationResult { /// <summary> /// Initializes a new instance of the <see cref="ValidationResult"/> class. /// </summary> public ValidationResult() { } /// <summary> /// Initializes a new instance of the <see cref="ValidationResult"/> class. /// </summary> /// <param name="memeberName">Name of the memeber.</param> /// <param name="message">The message.</param> public ValidationResult( string memeberName, string message) { MemberName = memeberName; Message = message; } /// <summary> /// Initializes a new instance of the <see cref="ValidationResult"/> class. /// </summary> /// <param name="message">The message.</param> public ValidationResult( string message) { Message = message; } /// <summary> /// Gets or sets the name of the member. /// </summary> /// <value> /// The name of the member. May be null for general validation issues. /// </value> public string MemberName { get ; set ; } /// <summary> /// Gets or sets the message. /// </summary> /// <value> /// The message. /// </value> public string Message { get ; set ; } } |
And now create the most used interface in this pattern. ICommandBus will be called as bus handler in every command:
1 2 3 4 5 6 7 8 9 | public interface ICommandBus { ICommandResult Send<TCommand>(TCommand command) where TCommand : ICommand; IEnumerable<ValidationResult> Validate<TCommand>(TCommand command) where TCommand : ICommand; } |
To implementing this interface, create a class again with the following definition:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | internal class CommandBus : ICommandBus { public ICommandResult Send<TCommand>(TCommand command) where TCommand : ICommand { var handler = DependencyResolver.Current.GetService<ICommandHandler<TCommand>>(); if (!((handler != null ) && handler != null )) { throw new CommandHandlerNotFoundException( typeof (TCommand)); } return handler.Execute(command); } public IEnumerable<ValidationResult> Validate<TCommand>(TCommand command) where TCommand : ICommand { var handler = DependencyResolver.Current.GetService<IValidationHandler<TCommand>>(); if (!((handler != null ) && handler != null )) { throw new ValidationHandlerNotFoundException( typeof (TCommand)); } return handler.Validate(command); } } |
The above class will handle every command received from the bus. And now for executing the handler or so-called for implementing the business, you need an interface:
1 2 3 4 5 6 7 | internal interface ICommandHandler< in TCommand> where TCommand : ICommand { ICommandResult Execute(TCommand command); } |
And finally as I’m personally interested in to have my own exception handler, so I create a customized handler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public class CommandHandlerNotFoundException : Exception { public CommandHandlerNotFoundException(Type type) : base ( string .Format( "Command handler not found for command type: {0}" , type)) { } } internal class ValidationHandlerNotFoundException : Exception { public ValidationHandlerNotFoundException(Type type) : base ( string .Format( "Validation handler not found for command type: {0}" , type)) { } } |
Finished! Now let’s use the above codes in a real work application. We are going to handle the products of an e-commerce application as its business is easier to comprehend for everybody:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | public interface IProductCommand : ICommand { string Name { get ; set ; } string OriginalName { get ; set ; } string Description { get ; set ; } decimal Price { get ; set ; } } public class ProductCommand : IProductCommand { public string Name { get ; set ; } public string OriginalName { get ; set ; } public string Description { get ; set ; } public decimal Price { get ; set ; } } public class CreateProductCommand : ProductCommand { } public class EditProductCommand : ProductCommand { public Guid ProductId { get ; set ; } public DateTime CreationDate { get ; set ; } public DateTime LastUpdateDate { get ; set ; } } public class DeleteProductCommand : ICommand { public Guid[] ProductIds { get ; set ; } } |
You can see that I created an interface derived from ICommand named IProductCommand and finally created the target classes. And at the end we should create the Product handler class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | internal partial class ProductCommandHandler : ICommandHandler<CreateProductCommand>, ICommandHandler<EditProductCommand>, ICommandHandler<DeleteProductCommand> { private readonly IProductRepository _productRepository; private readonly IMembershipRepository _membershipRepository; private readonly IUnitOfWork _unitOfWork; private readonly ICacheManager _cacheManager; private readonly ILogger _logger; public ProductCommandHandler( IProductRepository productRepository, IUnitOfWork unitOfWork, ILogger logger, ICacheManager cacheManager) { _productRepository = productRepository; _unitOfWork = unitOfWork; _logger = logger; _cacheManager = cacheManager; } public ICommandResult Execute(CreateProductCommand command) { try { if (command == null ) { throw new ArgumentNullException(); } var product = new Product(); AddProductAppurtenance(command, product); _productRepository.Add(product); _unitOfWork.Commit(); return new SuccessResult(ProductCommandMessage.ProductCreatedSuccessfully); } catch (Exception exception) { _logger.Error(exception.Message); return new FailureResult(ProductCommandMessage.ProductCreationFailed); } } public ICommandResult Execute(EditProductCommand command) { try { if (command == null ) { throw new ArgumentNullException(); } var product = _productRepository.GetProductDetailById(command.ProductId); ClearProductAppurtenance(product); AddProductAppurtenance(command, product); _productRepository.Edit(product); _unitOfWork.Commit(); return new SuccessResult(ProductCommandMessage.ProductEditedSuccessfully); } catch (Exception exception) { _logger.Error(exception.Message); return new FailureResult(ProductCommandMessage.ProductEditionFailed); } } public ICommandResult Execute(DeleteProductCommand command) { if (command.ProductIds == null ) { throw new ArgumentNullException(); } var exceptions = new List<Exception>(); foreach (var productId in command.ProductIds) { try { var product = DeleteProduct(productId); _productRepository.Edit(product); } catch (Exception exception) { exceptions.Add(exception); return new FailureResult(ProductCommandMessage.ProductDeletionFailed); } } if (exceptions.Any()) { throw new AggregateException(exceptions); } _unitOfWork.Commit(); return new SuccessResult(ProductCommandMessage.ProductsDeletedSuccessufully); } |
We used all of the classes introduced in infrastructure.
Note 1: so you need to have an IOC container tool, to the best of my Knowledge, AsClosedTypesOf in Autofac resolves the ICommandHandler. This a piece of code I wrote for IOC handler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class CommandModule : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterModule<RepositoryModule>(); builder.RegisterType<CommandBus>().As<ICommandBus>().InstancePerRequest(); builder.RegisterAssemblyTypes(ThisAssembly).AsClosedTypesOf( typeof (ICommandHandler<>)).InstancePerRequest(); } } |
Note 2: a penny for your thoughts! how to use ICommandBus!? See the below piece of code as an example:
1 2 3 4 5 6 7 8 9 10 11 | [HttpPost] public JsonResult DeleteProduct(DeleteProductCommand command) { var result = _commandBus.Send(command); return JsonMessage(result); } |
have fun.
Category: Software
Tags: Design Pattern Architecture