I have a workflow in which I need to use particular service class based on some run time data.
For eg. I have a SendEmailCommand
with a dependency of IEmailService
with 2 implementations of MandrillEmailService
and SmtpEmailService
.
The SendEmailCommand
will determine which implementation of IEmailService
it uses at run time.
Each Email Service implementation has its own dependencies, which is wired up by Simple Injector.
I'm not sure how SendEmailCommand
will determine what implementation (IEmailService
) to use or how to wire up those services with run time data.
Some code:
SendEmailCommand.cs handler
public void Handle(SendEmail command) {
IEmailService service;
if(/* some condition */) {
service = // What to do here?
} else {
service = // What to do here?
}
}
Service can be substituted with a strategy I'm guessing.
The most obvious solution (to me) is to define a new abstraction that allows dispatching to the mail service implementation while supplying the runtime data to it. This might look like this:
interface IMailServiceDispatcher
{
void Send([runtime data], [mail service arguments]);
}
This allows your command handler to become:
private readonly IEmailServiceDispatcher dispatcher;
public void Handle(SendEmail command) {
var data = /* runtime data */
this.dispatcher.Send(data, /* mail service parameters */);
}
Now you can create an implementation for IMailServiceDispatcher
that might look as follows:
class EmailServiceDispatcher : IEmailServiceDispatcher
{
IMailService man; IMailService smtp;
public EmailServiceDispatcher(IMailService man, IMailService smtp) { ... }
public void Send(runtimeData, parameters) =>
GetService(runtimedData).Send(parameters);
private IMailService GetService(runtimeData) =>
/* some condition using runtime data */ ? man : smtp;
}
You can wire this all up as follows:
container.Register<IMailServiceDispatcher, MailServiceDispatcher>();
container.RegisterConditional<IMailService, MandrillEmailService>(WithParamName("man"));
container.RegisterConditional<IMailService, SmtpEmailService>(WithParamName("smtp"));
// Helper method
private static Predicate<PredicateContext> WithParamName(string name) =>
c => c.Consumer.Target.Name == name;