Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass a parameter to the constructor using Simple Injector?

Does Simple Injector allow you to pass parameters to constructor when you resolve? I'd like to know if both these frameworks do what Unity's ResolverOverride or DependencyOverride both do.

like image 958
Ray Avatar asked Feb 14 '14 17:02

Ray


People also ask

Is simple injector safe?

Simple Injector is thread-safe and its lock-free design allows it to scale linearly with the number of available processors and threads.

Can we pass method in constructor?

can we pass a method as a constructor's parameter ? and why should we do this ? @T. shaped - yes you can and it depends on your scenario! You do not pass method itself but delegate (which is like a pointer to the method).

How can I pass a runtime parameter as part of the dependency resolution?

@AntSwift: Create a factory class, pass IServiceProvider to it, implement a "CreateMyService" method and pass the parameter to it, create/instantiate your class with the required parameter. Inject the factory into your controllers/services instead of the desired service.


Video Answer


4 Answers

I suspect that this question is about passing primitive values to the constructor at the time the service is actually resolved.

Let's set up a simple test class:

public interface IFoo
{

}

public class Foo : IFoo
{
    public Foo(string value)
    {

    }
}

The Foo class takes a string argument that we would like to supply when resolving the IFoo service.

var container = new ServiceContainer();
container.Register<string, IFoo>((factory, value) => new Foo(value));
var firstFoo = container.GetInstance<string, IFoo>("SomeValue");
var secondFoo = container.GetInstance<string, IFoo>("AnotherValue");

If we want to be able to create new instances of the Foo class without using the container directly, we can simply inject a function delegate.

public interface IBar { }

public class Bar : IBar
{
    public Bar(Func<string, IFoo> fooFactory)
    {
        var firstFoo = fooFactory("SomeValue");
        var secondFoo = fooFactory("AnotherValue");
    }
}

The "composition root" now looks like this:

var container = new ServiceContainer();
container.Register<string, IFoo>((factory, value) => new Foo(value));
container.Register<IBar, Bar>();
var bar = container.GetInstance<IBar>();

If the question is about passing a "static" primitive value to the contructor, this is simply done by registering a factory delegate like this.

var container = new ServiceContainer();
container.Register<IFoo>((factory) => new Foo("SomeValue"));
var firstInstance = container.GetInstance<IFoo>();
var secondInstance = container.GetInstance<IFoo>();

The difference is that this approach does not let you pass a value at resolve time. The value is statically specified at registration time.

like image 107
seesharper Avatar answered Oct 24 '22 03:10

seesharper


Probably the easiest option with Simple Injector is to register with a delegate

[Test]
public void Test1()
{
    Container container = new Container();

    container.Register<IClassWithParameter>(() => new ClassWithParameter("SomeValue"));

    var result = container.GetInstance<IClassWithParameter>();
}

public interface IClassWithParameter { }

public class ClassWithParameter : IClassWithParameter
{
    public ClassWithParameter(string parameter)
    {
    }
}

An advanced option for injecting primitive dependencies is detailed here

like image 31
qujck Avatar answered Oct 24 '22 02:10

qujck


The above will all work if your constructor does not have any other dependencies (or you want to resolve these dependencies manually). If you have the scenario below though it falls down:

public class Test : ITest
{
   private IFoo _foo;
   public Test(string parameter, IFoo foo)
   {
      _foo = foo;
      ....
   }
}

Now you not only have to manually inject the string but also Foo. So now your not using dependancy injection at all (really). Also Simple Injector state:

Simple Injector does not allow injecting primitive types (such as integers and string) into constructors.

My reading of this is that they're saying "don't do this".

Extensibillity points

Another option here is to use "Extensibillity points" for this scenario.

To do this you need to abstract your hard coded elements from your injected elements:

public class Test : ITest
{
   private IFoo _foo;
   public Test(IFoo foo)
   {
      _foo = foo;
      ....
   }

  public void Init(string parameter)
  {

  }
}

You can now inject your dependanices and your hardcoded elements:

_container.Register<ITest, Test>();
_container.RegisterInitializer<Test>(instance => {instance.Init("MyValue");});

If you now add another dependancy, your injection will now work without you having to update the config, i.e. your code is nicely de-coupled still:

public class Test : ITest
{
   private IFoo _foo;
   private IBar _bar;
   public Test(IFoo foo, IBar bar)
   {
      _foo = foo;
      _bar = bar;
      ....
   }

  public void Init(string parameter)
  {

  }
}
like image 40
Liam Avatar answered Oct 24 '22 01:10

Liam


In response to Liam's answer I would like to point out that there is a simpler way of doing this.

If you have the following situation:

public class Test : ITest
{
   private IFoo _foo;
   public Test(IFoo foo, string parameter)
   {
      _foo = foo;
      ....
   }
}

You could write your ioc configuration as below

_container.Register<IFoo, Foo>();
_container.Register<ITest>(
    () => new Test(
        _container.GetInstance<IFoo>(),
        "MyValue"
    )
);
like image 43
Jan Coppens Avatar answered Oct 24 '22 03:10

Jan Coppens