I use Windsor Castle quite a while now. It is just perfect for environments where data is located in a database or the like, where the repository pattern or the unitofwork pattern do work well.
Now I do have a different situation: I have a complex object model that is assembled by a lot of single PONOs. The environment is strongly influenced by COM, to make it more explicit: Excel, Word PIOs are heavily used.
I do use the command pattern, I implemented the ICommandHandler like described here but with one difference. As I do want to assembly commands to a list of commands to call them in a run without knowing anything beside the general command pattern described , it does not make to introduce the context when calling the execute method. So the interface does look like this:
public interface ICommand
{
void Execute();
bool CanExecute();
}
Execution of commands with that interface is effective and easy to understand. On the other hand it is a problem to introduce the context with the ctor because therefore the Container must be called explicitely to e.g. add ctor parameters.
So I actually have two questions:
Infrastructure:
public interface ICommandHandler<in T>
{
void Handle(T command);
}
public interface ICommandExecutor
{
CommandResult ExecuteCommand(Command command);
CommandResult ExecuteCommands(Command[] commands);
}
public abstract class Command
{
}
public class CommandExecutor : ICommandExecutor
{
private readonly IWindsorContainer _kernel;
public CommandExecutor(IWindsorContainer kernel)
{
Guard.AssertNotNull(() => kernel);
_kernel = kernel;
}
public CommandResult ExecuteCommand(Command command)
{
return ExecuteInternal(command);
}
public CommandResult ExecuteCommands(Command[] commands)
{
CommandResult result = null;
foreach (Command command in commands)
{
result = ExecuteInternal(command);
if (!result.IsExecuted)
return result;
}
return result ?? CommandResult.Executed("Command executed successfully");
}
private CommandResult ExecuteInternal(Command command)
{
dynamic handler = FindHandlerForCommand(command);
try
{
handler.Handle(command as dynamic);
return CommandResult.Executed("Command executed successfully");
}
finally
{
_kernel.Release(handler);
}
}
private object FindHandlerForCommand(Command command)
{
Type handlerType = typeof (ICommandHandler<>).MakeGenericType(command.GetType());
dynamic handler = _kernel.Resolve(handlerType);
return handler;
}
}
Registration:
container.Register(Component.For<ICommandExecutor>().ImplementedBy<CommandExecutor>()
.Interceptors<ExceptionToCommandResult>()
.Interceptors<ExceptionLogger>()
.Interceptors<HandleWhenDeadlockVictim>()
.Interceptors<RetryCommand>()
.Interceptors<ContainerScopeWrapper>()
.Interceptors<TransactionWrapper>()
.Interceptors<SameNhibernateSessionAndTransactionWrapper>());
Example:
public class WriteComment : Command
{
public string GameToCommentId { get; set; }
public string Comment { get; set; }
}
public class WriteCommentCommandHandler : ICommandHandler<WriteComment>
{
private readonly IGameRepository _repository;
public WriteCommentCommandHandler(IGameRepository repository)
{
Guard.AssertNotNull(() => repository);
_repository = repository;
}
public void Handle(WriteComment command)
{
var game = _repository.Get(new Guid(command.GameToCommentId));
game.WriteComment(command.Comment, DateTime.Now);
}
}
All that AOP stuff handles transactions and so forth. The command executor is a stateless singleton, the handlers specify their different needs. The command executor is just infrastructure and domain-agnostic, so place it where you like outside of your domain. This is production code on a big system, works like a charm.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With