Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setter / property injection in Unity without attributes

I am working on a project where the Unity framework is used as the IoC container. My question relates to injecting an optional dependency (in this case a logger) into several classes using property- or setter injection.

I do not want to clutter the constructors of all my classes with these optional dependencies, but I cannot find a good way to handle this in Unity. The way you would do this is, according to the MSDN documentation, by adding an attribute to the property:

private ILogger logger; 

[Dependency]
public ILogger Logger
{
get { return logger; }
  set { logger = value; }
}

I find this very ugly. In StructureMap one could do the following to set all properties of a given type:

SetAllProperties(policy => policy.OfType<ILog>());

Does anyone know if it is possible to do something similar in Unity?

Edit:

Kim Major suggests using this approach which can also be achieved through code.

I would be interested in examples of how to do this automatically for all matching properties.

like image 455
LittleBoyLost Avatar asked Feb 05 '09 08:02

LittleBoyLost


People also ask

Can you use dependency injection in unity?

Scene-based dependency injection means you can setup up the Unity hierarchy and your MonoBehaviors however you like. It scans your scene and automatically wires together your MonoBehaviors. It allows you to connect objects in the Unity hierarchy without having to manually use functions such as FindObjectOfType(...) .

What is Property injection?

Property injection is a type of dependency injection where dependencies are provided through properties. Visit the Dependency Injection chapter to learn more about it. Let's understand how we can perform property injection using Unity container. Consider the following example classes.

What is setter injection?

Setter injection is a dependency injection in which the spring framework injects the dependency object using the setter method. The call first goes to no argument constructor and then to the setter method. It does not create any new bean instance. Let's see an example to inject dependency by the setter method.

How do you inject a method in C#?

We have learned two patterns to implement Dependency Injection in C#. The first one is using constructor injection and the second one is property injection. You can read about them by visiting the following URLs.


3 Answers

I don't like those attributes also

You can do all using the Configure method of the unity container:

First register the type

unityContainer.RegisterType<MyInterface,MyImpl>(
                     new ContainerControlledLifetimeManager());

If you have multiple constructors you'll have to do this so Unity invokes the parameterless constructor (if none set Unity will go for the fattest one)

unityContainer.Configure<InjectedMembers>()
                            .ConfigureInjectionFor<MyImpl>(
                                new InjectionConstructor()); 

Setting property dependency

unityContainer.Configure<InjectedMembers>()
                    .ConfigureInjectionFor<MyImpl>(
                         new InjectionProperty(
                             "SomePropertyName",
                                new ResolvedParameter<MyOtherInterface>()));

Configuring method dependency

unityContainer.Configure<InjectedMembers>()
                    .ConfigureInjectionFor<MyImpl>(
                        new InjectionMethod(
                            "SomeMethodName",
                            new ResolvedParameter<YetAnotherInterface>()));
like image 189
t3mujin Avatar answered Oct 05 '22 06:10

t3mujin


I am also not a big fan of using attributes but I also don't like the .Configure<InjectedMembers>() method because you're bound to a specific property name and specific value. The way I've found that gives you the most flexibility is to create your own builder strategy.

I created this simple class that iterates the properties of an object being built up and sets its property values if the type of that property has been registered with the unity container.

public class PropertyInjectionBuilderStrategy:BuilderStrategy
{
    private readonly IUnityContainer _unityContainer;

    public PropertyInjectionBuilderStrategy(IUnityContainer unityContainer)
    {
        _unityContainer = unityContainer;
    }

    public override void PreBuildUp(IBuilderContext context)
    {
        if(!context.BuildKey.Type.FullName.StartsWith("Microsoft.Practices"))
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(context.BuildKey.Type);

            foreach (PropertyDescriptor property in properties)
            {
                if(_unityContainer.IsRegistered(property.PropertyType)
                   && property.GetValue(context.Existing) == null)
                {
                    property.SetValue(context.Existing,_unityContainer.Resolve(property.PropertyType));
                }
            }
        }
    }
}

You register your BuilderStrategy by creating a UnityContainerExtension. Here is an example:

public class TestAppUnityContainerExtension:UnityContainerExtension
{
    protected override void Initialize()
    {
        Context.Strategies.Add(new PropertyInjectionBuilderStrategy(Container), UnityBuildStage.Initialization);
    }
}

That gets registered with the Unity container as such:

IUnityContainer container = new UnityContainer();
container.AddNewExtension<TestAppUnityContainerExtension>();

Hope this helps,
Matthew

like image 44
Matthew Avatar answered Oct 05 '22 07:10

Matthew


The original example you posted does look very cumbersome, but you can use auto-implemented properties like this to help clean that code up:

[Dependency]
public ILogger Logger { get; set; }
like image 7
RamonH Avatar answered Oct 05 '22 06:10

RamonH