Without comment, the interfaces:
namespace Infrastructure.Command
{
public interface ICommand {}
public interface ICommand<TReturnValue> {}
public interface Handles<T> where T : ICommand
{
void Handle(T command);
}
public interface Handles<T,TReturnValue> where T: ICommand
{
TReturnValue Handle(T command);
}
public interface ICommandBus
{
void Register<TCommand>(Handles<TCommand> handler) where TCommand : ICommand;
void Publish<TCommand>(TCommand command) where TCommand : ICommand;
void Register<TCommand, TReturnValue>(Handles<TCommand, TReturnValue> handler) where TCommand : ICommand;
TReturnValue Publish<TCommand, TReturnValue>(TCommand command) where TCommand : ICommand;
}
public interface ICommandStore
{
void Store(ICommand command);
}
}
Without comment, an implementation:
using System;
using System.Collections.Generic;
using Infrastructure.Command;
namespace AdminLoader.Commands
{
public class InProcessCommandBus : ICommandBus
{
private Dictionary<Type, object> _handlers = new Dictionary<Type, object>();
private ICommandStore _store;
public InProcessCommandBus()
{
_store = new SqlCommandStore();
}
public void Register<TCommand>(Handles<TCommand> handler) where TCommand : ICommand
{
IList<Handles<TCommand>> handlers = GetHandlers<TCommand>();
handlers.Add(handler);
}
public void Publish<TCommand>(TCommand command) where TCommand : ICommand
{
_store.Store(command);
IList<Handles<TCommand>> handlers = GetHandlers<TCommand>();
if (handlers.Count == 0) throw new ApplicationException("No handlers exist for command of type " + command.GetType());
foreach (var commandHandler in handlers)
{
commandHandler.Handle(command);
}
}
private IList<Handles<TCommand>> GetHandlers<TCommand>() where TCommand : ICommand
{
Type commandType = typeof(TCommand);
object untypedValue;
if (!_handlers.TryGetValue(commandType, out untypedValue))
{
untypedValue = new List<Handles<TCommand>>();
_handlers.Add(commandType, untypedValue);
}
return (IList<Handles<TCommand>>)untypedValue;
}
private IList<Handles<TCommand, TReturnValue>> GetHandlers<TCommand, TReturnValue>() where TCommand : ICommand
{
Type commandType = typeof(TCommand);
object untypedValue;
if (!_handlers.TryGetValue(commandType, out untypedValue))
{
untypedValue = new List<Handles<TCommand, TReturnValue>>();
_handlers.Add(commandType, untypedValue);
}
return (IList<Handles<TCommand, TReturnValue>>)untypedValue;
}
public void Register<TCommand, TReturnValue>(Handles<TCommand, TReturnValue> handler) where TCommand : ICommand
{
IList<Handles<TCommand, TReturnValue>> handlers = GetHandlers<TCommand, TReturnValue>();
handlers.Add(handler);
}
public TReturnValue Publish<TCommand, TReturnValue>(TCommand command) where TCommand : ICommand
{
_store.Store(command);
IList<Handles<TCommand, TReturnValue>> handlers = GetHandlers<TCommand, TReturnValue>();
Handles<TCommand, TReturnValue> handler = handlers[0];
return handler.Handle(command);
}
}
}
And:
namespace AdminLoader.Commands
{
public class InProcessAdminLoaderCommandBus : InProcessCommandBus
{
public InProcessAdminLoaderCommandBus()
{
Register(new CreateNewUserWithAppAndRoleCommandHandler());
Register(new DeleteExistingUserCommandHandler());
}
}
}