I’m not sure if this is possible, but I though I’d ask the question anyway.
I have a scenario where I have a number of different tasks which send emails during processing.
The sending of emails is done via a custom class
public interface IEmailProvider
{
void SendEmail(some params);
}
public class EmailProvider : IEmailProvider
{
private readonly IEmailConfig _config;
public EmailProvider(IEmailConfig config)
{
_emailConfig = emailConfig;
}
public void SendEmail(some params)
{
// send the email using the params
}
}
I have some tasks which use the email provider, each providing their own implementation of IEmailConfig.
public class Task1 : ICommand
{
public Task1(IEmailProvider emailProvider)
{}
}
public class Task2 : ICommand
{
public Task2(IEmailProvider emailProvider)
{}
}
This is a basic example of my set up
public class TestInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// Default email provider set up
container.Register(Component.For<IEmailProvider>().ImplementedBy<EmailProvider>()
.Named("DefaultEmailProvider")
.LifeStyle.Transient);
// Task 1 email config set up
container.Register(Component.For<IEmailConfig>().ImplementedBy<Task1EmailConfig>()
.Named("Task1EmailConfig"));
// Task 2 email config set up
container.Register(Component.For<IEmailConfig>().ImplementedBy<Task2EmailConfig>()
.Named("Task2EmailConfig"));
// Task 1 set up
container.Register(Component.For<ICommand>().ImplementedBy<Task1>()
.Named("Task1Command"));
// Task 2 set up
container.Register(Component.For<ICommand>().ImplementedBy<Task2>()
.Named("Task2Command"));
}
}
Is there a way I can make a decision, as each ICommand implementation is being resolved, as to which implementation of IEmailConfig to pass into the constructor of the EmailProvider class?
At the moment I register an EmailProvider instance for each task using the ServiceOverride functionality. This means that for each task that need to send emails, I have to almost duplicate the set up of the email provider and it’s required config. I end up with something list this…
Component.For<IEmailConfig>()
.ImplementedBy<Task1EmailConfig>()
.Named("Task1EmailConfig"));
Component.For<IEmaiProvider>()
.ImplementedBy<EmailProvider>)
.Named("Task1EmailProvider")
.DependsOn(ServiceOverride.ForKey("config").Eq("Task1Config"));
Component.For<ICommand>()
.ImplementedBy<Task1>()
.DependsOn(ServiceOverride.ForKey("emailProvider").Eq("Task1EmailProvider")));
This will all be duplicated for each task.
The IEmailProvider implementation is always the same, it’s only the IEmailConfig passed in that changes for each different task. I can’t help thinking there must be a neater solution to the one I’ve got so far.
I think a couple of handler selectors would work for what you want. One for IEmailProvider and one for ICommand.
The IEmailProvider one could check the name of the IEmailProvider being activated (like “Task1EmailProvider”) and strip off the “Provider” and add on “Config” — which would give you the key “Task1EmailConfig” which could be used to resolve the particular IEmailConfig object.
Likewise, do the same thing for ICommand’s. It would rely on you naming your IEmailConfig’s consistently, but it would eliminate all of that hand-wiring you’re doing now.