Lets assume these classes/interfaces:
public interface ICommand
{
}
public class SomeCommand : ICommand
{
}
public interface ICommandHandler<T> where T : ICommand
{
void Handle(T arg);
}
public class SomeCommandHandler : ICommandHandler<SomeCommand>
{
void Handle(SomeCommand arg){ /* do something */ }
}
public interface ICommandBus
{
void RegisterHandler<T>(T t) where T : ICommandHandler<T>;
void RegisterHandlerByParam<T2>(ICommandHandler<T2> t2) where T2 : ICommand;
void RegisterHandlerMethod<T3>(Action<T3> action) where T3 : ICommand
}
public class TheCommandBus : ICommandBus
{
// implements ICommandBus ...
}
I want to register all implementations of ICommandHandler<> automatically. All variants (Register*) are valid solutions even though I would prefer Action parameter while it is more flexible and has no dependency to Handler interface (just action delegate).
Autofac has the capability to register types based upon assembly scanning and register the found implementations of a generic interface, for example:
builder.RegisterAssemblyTypes(Assembly.LoadFrom("MyAssembly.dll"))
.AsClosedTypesOf(typeof(ICommandHandler<>));
So I have all implementations registered. Now I need to Register them all automatically to TheCommandBus. How to do that?
I can do this manually by adding those lines (e.g. during OnActivated):
builder.RegisterType<TheCommandBus>().As<ICommandBus>().OnActivated(args =>
{
// now I need to list all implementations here!!! please, no...
args.Instance.RegisterHandler<ICommandHandler<SomeCommand>>(args.Context.Resolve<ICommandHandler<SomeCommand>>());
// does not look better to me than before ...
args.Instance.RegisterHandlerByParam<SomeCommand>(args.Context.Resolve<ICommandHandler<SomeCommand>>())
// uses delegate for, but still need to list all variants
args.Instance.RegisterHandlerMethod<SomeCommand>(args.Context.Resolve<ICommandHandler<SomeCommand>>().Handle)
});
If I want to use such a type in a lambda expression during registration I have the problem, that I need to identify the concrete type, like for this example on activation process for another component. But I don't want to list all of them manually... want something like this automatically.
How do I catch all ICommandHandler implementations AND have them automatically registered with the Register* method?
Edit:
Another variant is to extend the SomeCommandHandler class to register itself when resolved inside its constructor:
public SomeCommandHandler(ICommandBus commandBus)
{
// and register here, for example
commandBus.RegisterHandlerbyParam(this);
}
This way I have to provide AutoActivate() to the AsClosedTypesOf registration result. (a possible solution, but now the "handlers" have two responsibilities... registration and handling)