Here's my scenario:
public static class DomainCommandProcessor
{
public static void Dispatch<T>(T command) where T : IDomainCommand
{
var serviceLocator = ServiceLocator.Current;
var handler = serviceLocator.GetInstance<IDomainCommandHandler<T>>();
if (handler != null)
handler.Handle(command);
}
}
public class FakeGenericCommand<T1, T2> : IDomainCommand
{
public FakeGenericCommand(T1 first, T2 second)
{
First = first;
Second = second;
}
public T1 First { get; private set; }
public T2 Second { get; private set; }
}
public class FakeGenericCommandHandler<T1, T2> : IDomainCommandHandler<FakeGenericCommand<T1, T2>>
{
public void Handle(FakeGenericCommand<T1, T2> command)
{
// something interesting
}
}
Usage:
DomainCommandProcessor.Dispatch(new FakeGenericCommand<string, string>("hi", "there"))
I can't get the Windsor registration right. The following works great for all of my non-generic commands:
container.Register(Classes.FromAssemblyNamed(namespaceName)
.BasedOn(typeof(IDomainCommandHandler<>))
.WithService.AllInterfaces()
.LifestyleTransient());
If I register each possible implementation directly, it works but is obviously sub-optimal:
container.Register(
Component.For<IDomainCommandHandler<FakeGenericCommand<string, string>>>()
.UsingFactoryMethod(input => new FakeGenericCommandHandler<string, string>())
.LifestyleTransient());
Suggestions?
What you have here is a textbook-case of needing a typed factory: I answered a question where I described how to use it
This answer is heavily inspired by this article.
Register all your handlers
Declare a factory interface that will return the handlers for a command
You need to link your command types to the handlers, which you can do with a custom selector:
Then tell Windsor you want a factory that will return a
IDomainCommandHandler<T>
. Don't code anything for the factory.You can now use the factory to retrieve your handlers for a command
Please note that the handlers in the example are not running against the command itself but have a
Execute
function. If you want to return closed generic objects you need to cast them after resolution since you cannot return different types from one method.I'd advise you reading the original article since it also contains additional information regarding lifestyle, releasing of components and other interesting points.
Here an example of the Selector I use for requests where I specify the request and the response as generic components
And here is the result of the call to the factory (T is the request, R the response)