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.
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(...) .
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.
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.
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.
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>()));
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
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; }
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