I have an IConfig
object that contains settings used throughout my application. At the moment, I inject the entire object into the constructor of each object that needs it, as follows:
public interface IConfig
{
string Username { get; }
string Password { get; }
//... other settings
}
public class Foo : IFoo
{
private readonly string username;
private readonly string password;
public Foo(IConfig config)
{
this.username = config.Username;
this.password = config.Password;
}
}
The downside is that IConfig
contains a large number of settings because it's deserialised from an overall config file, so injecting the entire object is unnecessary. What I'd like to do is change the constructor to Foo(string username, string password)
so that it only receives the settings it needs. This also makes creating Foo
objects for testing much easier (not having to set up IConfig
just to create Foo
). I'd like to bind the constructor arguments directly in my NinjectModule
, something like the following:
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IConfig>().To<JsonConfig>()
.InSingletonScope();
Bind<IFoo>().To<Foo>()
.WithConstructorArgument("username", IConfig.Username)
.WithConstructorArgument("password", IConfig.Password);
}
}
Obviously this code doesn't work, but how would I go about doing what I wanted?
My original idea was to use the NinjectModule.Kernel
to get the IKernel
then get an instance of my IConfig
object and inject the properties as required, but the object returned by NinjectModule.Kernel
has no Get<T>()
method.
You are on the right track:
The Kernel.Get<T>()
method is an extension method defined on the ResolutionExtensions
in the Ninject
namepsace so with adding the using Ninject;
it is available in your module as well.
But instead of the Module.Kernel
you should use the IContext
provided in the second overload of WithConstructorArgument
to get the Kernel
:
Bind<IFoo>().To<Foo>()
.WithConstructorArgument("username",
context => context.Kernel.Get<IConfig>().Username)
.WithConstructorArgument("password",
context => context.Kernel.Get<IConfig>().Password);
This could be a good candiate for the Interface segregation principle.
In this case, define another interface such as an ICredentialConfig
containing just the Username
and Password
properties, then make IConfig
implement this interface.
public Interface ICredentialConfig
{
string Username { get; }
string Password { get; }
}
public Interface IConfig : ICredentialConfig
{
//... other settings
}
Now make Foo
dependant on ICredentialConfig
instead of IConfig
.
You can then:
JsonConfig
using Ninject, instead of having hardcoded parameter names.ICredentialConfig
for instantiating Foo
in tests, instead of having to implement the full IConfig
interface.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With