Griffin.Container: Introducing the command support
A command which is used together with Griffin.Container can look like this:
public class CreateUser : ICommand
{
public CreateUser(string firstName, string lastName)
{
if (firstName == null) throw new ArgumentNullException('firstName');
if (lastName == null) throw new ArgumentNullException('lastName');
FirstName = firstName;
LastName = lastName;
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
}
Notice that the commands are immutable and do not return a value. A command should always validate all entered information (always catch errors as early as possible). Mandatory fields should be specified in the constructor while optional is set through methods or properties.
That is important if you want to be able to scale your application later on. You can for instance at any time serialize the command and send it to another server, thanks to that the command is immutable and do not return value is expected. I’ll demonstate how you can achieve that using decorators and Griffin.Networking in a later blog post.
Let’s focus on the command now. We need to dispatch it in some way so that it can be invoked.
Here is an example ASP.NET MVC3 controller:
public class UserController : Controller
{
ICommandDispatcher _dispatcher;
public UserController(ICommandDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
[HttpPost, Transactional]
public ActionResult Create(CreateModel model)
{
if (!ModelState.IsValid)
return View(model);
var cmd = new CreateCommand(model.FirstName, model.LastName);
_dispatcher.Dispatch(cmd);
return RedirectToAction('List');
}
}
We do not know where the command is invoked, we should really not care either. We could even go a step further and not care about when the command is executed (as long as we have some kind of notification system to inform the user of failed commands). It all depends on how scalable your application should be (now or later).
We could start with an application where everything is synchronous and executed in the same process and end up with a application where the commands are distributed over several servers.
Getting a result
Commands should not return a result. It complicates the command handling and forces everything to be synchronous (or even more complex). It’s of course a trade off, but it also makes everything more flexible.
You still have the information which you used to invoke the command. You can use that information to update the UI to fake that a new item has been created/updated (which it will eventually). You could also inform the user that the item has been handled and that he need to refresh the UI to see it.
If you need an ID, switch to GUIDs and generate and attach it to the command before invoking it. There are GUIDs which works well with databases.
Handling the command
Commands are handled by classes which implements the interface IHandlerOf<T>
.
A typical implementation looks something like this:
[Component]
public class CreateUserHandler : IHandlerOf<CreateUser>
{
private IUserRepository _repository;
public CreateUserHandler(IUserRepository repository)
{
_repository = repository;
}
public void Invoke(CreateUser cmd)
{
var user = _repository.Create(cmd.FirstName, cmd.LastName);
DomainEvent.Publish(new UserCreated(user));
}
}
The [Component]
attribute will allow you to automatically register the class in the container. Read more about that in the core documentation
Nesting commands
No. Do not nest commands. A command is created for a specific use case. It’s not intended to get reused. Nesting commands can quickly produce complex code which is hard to follow and maintain.
Instead break out common functionality to a third class which is used by both commands. Decorators
Decorators allows you to add functionality to the command handlers without actually having to modify them.
You could for instance create an decorator which meassure the performance of every command. It would look something like this:
public class PerformanceMonitor<T> : IHandlerOf<T> where T : class, ICommand
{
private readonly IHandlerOf<T> _inner;
public PerformanceMonitor(IHandlerOf<T> inner)
{
_inner = inner;
}
public void Invoke(T command)
{
var w = new Stopwatch();
w.Start();
_inner.Invoke(command);
w.Stop();
Console.WriteLine('Invocation of {0} took {1}ms.', command.GetType().Name, w.ElapsedMilliseconds);
}
}
All decorators are attached the the handlers by using factories. A factory which would attach the performance decorator to all commands would look something like:
[Component]
public class ExceptionDecoratorFactory : IDecoratorFactory
{
// used to determine which commands to decorate
public bool CanDecorate(Type commandType)
{
return true;
}
// invoked if we can decorate a command
public IHandlerOf<T> Create(IHandlerOf<T> inner) where T : class, ICommand
{
return new PerformanceMonitor(inner);
}
}
The factory itself should be added to the container. The command dispatcher automatically finds all factories which have been registered.
Exception decorator
A decorator called ExceptionDecorator<T>
is included in the framework. It automatically logs all failed commands and their properties.
Example output:
FailureCommand
Parameters:
FirstName: Arne
Exception:
System.InvalidOperationException: That wont work, dude!
at Griffin.Container.Tests.Commands.DecoratorTests.FailureHandler.Invoke(FailureCommand command) in C:\projects\csharp\gauffin\Griffin.Container\Source\Griffin.Container.Tests\Commands\DecoratorTests.cs:line 53
at Griffin.Container.Tests.Commands.DecoratorTests.PerformanceMonitor`1.Invoke(T command) in C:\projects\csharp\gauffin\Griffin.Container\Source\Griffin.Container.Tests\Commands\DecoratorTests.cs:line 39
at Griffin.Container.Commands.ExceptionDecorator`1.Invoke(T command) in C:\projects\csharp\gauffin\Griffin.Container\Source\Griffin.Container\Commands\ExceptionDecorator.cs:line 39
Validation decorator
There is also a validation decorator included that is used to validate properties on the commands. It uses DataAnnotation attributes for the validation.
Example command (required parameters are manually validated in the constructor while optional properties is validated using DataAnnotations):
public class CreateUser : ICommand
{
public CreateUser(string firstName, string lastName)
{
if (firstName == null) throw new ArgumentNullException('firstName');
if (lastName == null) throw new ArgumentNullException('lastName');
FirstName = firstName;
LastName = lastName;
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
[StringLength(40)]
public string Title { get; set; }
}
Getting the code
The code is available at github and is included in the main project.
You can get it by using nuget: install-package griffin.container
.
Reference: Griffin.Container: Introducing the command support. from our NCG partner Jonas Gauffin at the jgauffin’s coding den blog.