Tengo el siguiente:StructureMap registrar tipos genéricos contra todas las posibles implementaciones concretas
public interface ICommand { }
public class AddUser : ICommand
{
public string Name { get; set; }
public string Password { get; set; }
}
public interface ICommandHandler<T> : IHandler<T> where T : ICommand
{
void Execute(T command);
}
public class AddUserHandler : ICommandHandler<AddUser>
{
public void Execute(AddUser command)
{
Console.WriteLine("{0}: User added: {1}", GetType().Name, command.Name);
}
}
public class AuditTrailHandler : ICommandHandler<ICommand>
{
public void Execute(ICommand command)
{
Console.WriteLine("{0}: Have seen a command of type {1}", GetType().Name, command.GetType().Name);
}
}
me gustaría utilizar el escaneado para registrar el ICommandHandler <> de modo que consiga los siguientes tipos en el contenedor:
ICommandHandler<AddUser>
con el tipo concretoAddUserHandler
ICommandHandler<AddUser>
con el tipo concretoAuditTrailHandler
He intentado esto con una implementación de IRegistrationConvention y en un momento lo tuve funcionando, pero no entiendo cómo lo hice.
El objetivo es ser capaz de ejecutar varios controladores para una aplicación específica ICommand así:
// A method in CommandDispatcher
public void SendCommand<T>(T command) where T : ICommand {
var commandHandlers = container.GetAllInstances<ICommandHandler<T>>();
foreach (var commandHandler in commandHandlers) {
commandHandler.Execute(command);
}
}
Quiero que el AuditTrailHandler<ICommand>
a ejecutar para todas las implementaciones concretas de ICommand, de ahí la necesidad de registrarlos para todos tipos de ICommand.
El objetivo secundario sería si pudiera inyectar una colección de ICommandHandlers<ICommand>
en mi CommandDispatcher en lugar del contenedor, pero creo que eso es imposible con la estructura que tengo ahora. Demuestre que estoy equivocado si tiene alguna idea.
EDITAR - resuelto
que añade una interfaz genérica que no implementa la interfaz mis genérico y luego tambien tiene añadido un extracto CommandHandler<T>
así que no tienen que poner en práctica el CanHandle o Ejecutar (objeto) en todos los métodos mis manejadores.
Esta es la estructura de trabajo:
public interface ICommandHandler
{
void Execute(object command);
bool CanHandle(ICommand command);
}
public interface ICommandHandler<T> : ICommandHandler, IHandler<T> where T : ICommand
{
void Execute(T command);
}
public abstract class AbstractCommandHandler<T> : ICommandHandler<T> where T : ICommand
{
public abstract void Execute(T command);
public void Execute(object command)
{
Execute((T)command);
}
public virtual bool CanHandle(ICommand command)
{
return command is T;
}
}
Y puesto que este principio era una pregunta StructureMap, aquí es la función Escanear a añadir lo siguiente:
Scan(x =>
{
x.AssemblyContainingType<MyConcreteHandler>();
x.IncludeNamespaceContainingType<MyConcreteHandler>();
x.AddAllTypesOf<ICommandHandler>();
x.WithDefaultConventions();
});
Esto me hace capaz de inyectar un IEnumerable en mi CommandDispatcher y ejecutar así:
public void SendCommand<T>(T command) where T : ICommand
{
var commandHandlersThatCanHandle = commandHandlers.Where(c => c.CanHandle(command));
foreach (var commandHandler in commandHandlersThatCanHandle)
{
commandHandler.Execute(command);
}
}
Esto me permite ejecutar Com mandHandlers que son compatibles con AddUser (como AddUserHandler), pero también puedo ejecutar un controlador que admita ICommand (como AuditTrailHandler).
Esto es dulce!
¡Eso es brillante! Tuve el método CanHandle anteriormente, pero lo eliminé porque pensé que la magia de StructureMap podría hacerlo por mí. Incluso fui un poco más allá e hice un CommandHandler abstracto y puse eso entre la interfaz genérica y la clase concreta, de modo que puedo beneficiarme del método CanHandle sin tener que implementarlo en todas las clases derivadas. ¡Increíble, gracias! –