Brian Mains
Brian Mains

Reputation: 50728

SimpleInjector does not inject property using Implicit Property Injection

I have an ObjectA, which has a property for ObjectB, which has a property for ObjectC, which are all in the Simple Injector container. When I create ObjectA, I call InjectProperties on it, which loads up ObjectB. However, at this time, it does not load up the reference to ObjectC within the newly created ObjectB; it does not perform what I'll call a "deep buildup" of objects.

Is there a way to enable this?

EDIT

I have a class object A:

public class ObjectA
{
     public ObjectB InstanceB { get; set; }
}

Which has a property to ObjectB:

public class ObjectB
{
     public ObjectC InstanceC { get; set; }
}

All have been registered using the standard register method on the container. To get ObjectA, I use GetInstance<ObjectA>(), and this comes back fine, I also built an initializer to build up all objects upon creation:

_container.RegisterInitializer<object>(i => _container.InjectProperties(i));

This injects ObjectB into ObjectA, but does not then inject ObjectC into ObjectB, at the time it resolves ObjectB.

Is there a workaround? Thanks.

Upvotes: 2

Views: 1356

Answers (1)

Steven
Steven

Reputation: 172676

I wrote a little test using your code and your configuration (and added the missing ObjectC):

public class ObjectA
{
    public ObjectB InstanceB { get; set; }
}

public class ObjectB
{
    public ObjectC InstanceC { get; set; }
}

public class ObjectC
{

}

The test:

[TestMethod]
public void ImplicitPropertyInjectionTest()
{
    // Arrange
    var container = new Container();

    container.RegisterInitializer<object>(
        i => container.InjectProperties(i));

    // Act
    var a = container.GetInstance<ObjectA>();

    // Assert
    Assert.IsNotNull(a.InstanceB);
    Assert.IsNotNull(a.InstanceB.InstanceC);
}

The test succeeds and InstanceC is correctly injected. I expect there to be something wrong with your configuration or perhaps ClassC can not be created. Try requesting ClassC directly to find out why the container can not create it:

container.GetInstance<ClassC>();

This line will probably fail and that's the reason that InstanceC is not injected.

This directly brings me at the following:

Calling RegisterInitializer<object>(instance => container.InjectProperties(instance)) like you did, is an effective way to enable implicit property injection, but you should avoid using implicit property injection as much as possible, since this leads to a container configuration that can not be verified (by using container.Verify() for instance). You already noticed this, because InstanceC was skipped over. Instead you should use constructor injection as much as possible. See more information about writing your code in a way that it can be verified here.

If it is impossible to use constructor injection in certain scenarios, prefer using explicit property injection, which is done as follows:

container.RegisterInitializer<ClassA>(a =>
{
    a.InstanceB = container.GetInstance<ClassB>();
});

container.RegisterInitializer<ClassB>(b =>
{
    b.InstanceC = container.GetInstance<ClassC>();
});

This explicitly injects properties InstanceB and InstanceC, and will fail construction when the properties can not be injected.

More about doing property injection with Simple Injector can be found here.

Last note. Please note that all containers behave about the same when it comes to implicit property injection. So this is not specific to the Simple Injector. If this feature is supported by that container, it will skip every property that can't be injected. In other words, all containers will fail silently and continue, which is typically not what you want. This means that you have to be extra careful when working with a container that enables implicit property injection by default.

Upvotes: 3

Related Questions