Search code examples
c#inversion-of-controlsimple-injector

SimpleInjector: Registration of class that has data parameters, and a dependency


Registration of a service that has only data parameters in it's ctor is easy enough.

string emailHost = "emailHost";
int emailPort = 25;
string emailFrom = "fake@fake.cc";

container.Register<IEmailManager>(
    () => new EmailManager(emailHost, emailPort, emailFrom),
    Lifestyle.Singleton);

But how do I do it if the class/service has data paramters, and an injected service? How can I get that registered SmsNumberFormatter into SmsManager, which still providing the sms configuration data via ctor?

string smsAccountSid = "sid";
string smsAuthToken = "token";
string smsFromNumber = "##########";

container.Register<ISmsNumberFormatter, SmsNumberFormatter>(
    Lifestyle.Singleton);

container.Register<ISmsManager>(
    () => new SmsManager(
        new SmsNumberFormatter(), smsAccountSid, smsAuthToken, smsFromNumber), 
    Lifestyle.Singleton);

SimpleInjector: v 3.3.2.0


Solution

  • You have two options:

    1. Use the container to obtain your dependency

    container.Register<ISmsManager>(() => 
            new SmsManager(container.GetInstance<ISmsNumberFormatter>(),
            smsAccountSid, 
            smsAuthToken, 
            smsFromNumber), Lifestyle.Singleton);
    

    2. Turn your basic type parameters into a single injectable class

    public class SmsManagerOptions
    {
        public SmsManagerOptions(string smsAccountSid, string smsAuthToken, string smsFromNumber)
        {
            SmsAccountSid = smsAccountSid ?? throw new ArgumentNullException(nameof(smsAccountSid));
            SmsAuthToken = smsAuthToken ?? throw new ArgumentNullException(nameof(smsAuthToken));
            SmsFromNumber = smsFromNumber ?? throw new ArgumentNullException(nameof(smsFromNumber));
        }
    
        public string SmsAccountSid { get; }
        public string SmsAuthToken { get; }
        public string SmsFromNumber { get; }
    }
    

    You than need, of course, to change the SmsManager ctor to something like public SmsManager(ISmsNumberFormatter formatter, SmsManagerOptions options).

    Then in your DI registration method:

    var options = new SmsManagerOptions("sid", "token", "######");
    
    container.Register<ISmsNumberFormatter, SmsNumberFormatter>(Lifestyle.Singleton);
    container.RegisterSingleton<SmsManagerOptions>(options);
    container.Register<ISmsManager, SmsManager>(Lifestyle.Singleton);
    

    Note

    I believe the second option is cleaner, but you are free to choose the one you like.