Annotating Objects for Property (Setter) Injection
Unity supports dependency injection to set the values or properties through attributes applied to members of the target class. You can use the Unity container to generate instances of dependent objects and wire up the target class properties with these instances. This topic explains how to use an attribute that is applied to one or more property declarations of a class to define the dependency injection requirements of that class. The attribute can specify parameters for the attribute to control its behavior, such as the name of a registered mapping.
To perform property injection of dependent classes into objects you create through the Unity container, you apply the Dependency attribute to the property declarations of a class. The Unity container will create an instance of the dependent class within the scope of the target object (the object you specify in a Resolve method call) and assign this dependent object to the attributed property of the target object.
Property injection is a form of optional injection of dependent objects, as long as developers use the Unity container to generate the target object. The dependent object instance is generated before the container returns the target object. In addition, unlike constructor injection, you must apply the appropriate attribute in the target class to initiate property injection. You can also perform property injection of optional dependent classes by applying the OptionalDependency attribute. This simply marks a dependency as optional, which means that the container will try to resolve it, and return null if the resolution fails rather than throw an exception. For more information, see Notes on Using Property (Setter) Injection.
To use property (setter) injection to create dependent objects for a class
Define a property in the target class and apply the Dependency attribute to it to indicate that the type defined and exposed by the property is a dependency of the class. The following code demonstrates property injection for a class named MyObject that exposes as a property a reference to an instance of another class named SomeOtherObject (not defined in this code).
public class MyObject { private SomeOtherObject _dependentObject; [Dependency] public SomeOtherObject DependentObject { get { return _dependentObject; } set { _dependentObject = value; } } }
Public Class MyObject Private _dependentObject As SomeOtherObject <Dependency()> _ Public Property DependentObject() As SomeOtherObject Get Return _dependentObject End Get Set(ByVal value As SomeOtherObject) _dependentObject = value End Set End Property End Class
In your run-time code, use the Resolve method of the container to create an instance of the target class, and then reference the property containing the dependent object. The Unity container will instantiate the dependent concrete class defined in the attributed property and inject it into the target class. For example, the following code shows how you can instantiate the example target class named MyObject containing an attributed property that has a dependency on a class named SomeOtherObject and then retrieve the dependent object from the DependentObject property.
IUnityContainer uContainer = new UnityContainer(); MyObject myInstance = uContainer.Resolve<MyObject>(); // now access the property containing the dependency SomeOtherObject depObj = myInstance.DependentObject;
Dim uContainer As IUnityContainer = New UnityContainer() Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)() ' now access the property containing the dependency Dim depObj As SomeOtherObject = myInstance.DependentObject
In addition to using concrete types for the dependencies in target object properties, you can use interfaces or base class types, and then register mappings in the Unity container to translate these types into the correct concrete types. Define a property in the target class as an interface or base type. For example, the following code shows a target class named MyObject containing properties named InterfaceObject and BaseObject that have dependencies on a class that implements the interface named IMyInterface and on a class that inherits from MyBaseClass.
public class MyObject { private IMyInterface _interfaceObj; private MyBaseClass _baseObj; [Dependency] public IMyInterface InterfaceObject { get { return _interfaceObj; } set { _interfaceObj = value; } } [Dependency] public MyBaseClass BaseObject { get { return _baseObj; } set { _baseObj = value; } } }
Public Class MyObject Private _interfaceObj As IMyInterface Private _baseObj As MyBaseClass <Dependency()> _ Public Property InterfaceObject() As IMyInterface Get Return _interfaceObj End Get Set(ByVal value As IMyInterface) _interfaceObj = value End Set End Property <Dependency()> _ Public Property BaseObject() As MyBaseClass Get Return _baseObj End Get Set(ByVal value As MyBaseClass) _baseObj = value End Set End Property End Class
In your run-time code, register the mappings you require for the interface and base class types, and then use the Resolve method of the container to create an instance of the target class. The Unity container will create an instance of each of the mapped concrete types for the dependent classes and inject them into the target class. For example, the following code shows how you can instantiate the example target class named MyObject containing two properties that have dependencies on the two classes named FirstObject and SecondObject.
IUnityContainer uContainer = new UnityContainer() .RegisterType<IMyInterface, FirstObject>() .RegisterType<MyBaseClass, SecondObject>(); MyObject myInstance = uContainer.Resolve<MyObject>(); // now access the properties containing the dependencies IMyInterface depObjA = myInstance.InterfaceObject; MyBaseClass depObjB = myInstance.BaseObject;
Dim uContainer As IUnityContainer = New UnityContainer() _ .RegisterType(Of IMyInterface, FirstObject)() _ .RegisterType(Of MyBaseClass, SecondObject)() Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)() ' now access the properties containing the dependencies Dim depObjA As IMyInterface = myInstance.InterfaceObject Dim depObjB As MyBaseClass = myInstance.BaseObject
You can register multiple named mappings with the container for each dependency type, if required, and then use a parameter of the Dependency attribute to specify the mapping you want to use to resolve the dependent object type. For example, the following code specifies the mapping names for the Key property of the Dependency attribute for two properties of the same type (in this case, an interface) in the class MyObject.
public class MyObject { private IMyInterface _objA, _objB; [Dependency("MapTypeA")] public IMyInterface ObjectA { get { return _objA; } set { _objA = value; } } [Dependency("MapTypeB")] public IMyInterface ObjectB { get { return _objB; } set { _objB = value; } } }
Public Class MyObject Private _objA, _objB As IMyInterface <Dependency("MapTypeA")> _ Public Property ObjectA() As IMyInterface Get Return _objA End Get Set(ByVal value As IMyInterface) _objA = value End Set End Property <Dependency("MapTypeB")> _ Public Property ObjectB() As IMyInterface Get Return _objB End Get Set(ByVal value As IMyInterface) _objB = value End Set End Property End Class
In your run-time code, register the named (non-default) mappings you require for the two concrete types that the properties will depend on, and then use the Resolve method of the container to create an instance of the target class. The Unity container will instantiate an instance of each of the mapped concrete types for the dependent classes and inject them into the target class. For example, the following code shows how you can instantiate the example target class named MyObject containing two properties that have dependencies on the two classes named FirstObject and SecondObject.
IUnityContainer uContainer = new UnityContainer() .RegisterType<IMyInterface, FirstObject>("MapTypeA") .RegisterType<IMyInterface, SecondObject>("MapTypeB"); MyObject myInstance = uContainer.Resolve<MyObject>(); // now access the properties containing the dependencies IMyInterface depObjA = myInstance.ObjectA; IMyInterface depObjB = myInstance.ObjectB;
Dim uContainer As IUnityContainer = New UnityContainer() _ .RegisterType(Of IMyInterface, FirstObject)("MapTypeA") _ .RegisterType(Of IMyInterface, SecondObject)("MapTypeB") Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)() ' now access the properties containing the dependencies Dim depObjA As IMyInterface = myInstance.ObjectA Dim depObjB As IMyInterface = myInstance.ObjectB
Using Optional Dependencies
An optional dependency works like a regular dependency with the difference that if the optional dependency cannot be resolved, null is returned by the container.
public class ObjectWithOptionalProperty
{
[OptionalDependency]
public ICarInterface Car
{
…. get;
…. set;
}
}
Public Class ObjectWithOptionalProperty
..<OptionalDependency> _
..Public Property Car() As ICarInterface
Get
End Get
Set
End Set
..End Property
End Class
Notes on Using Property (Setter) Injection
Remember that property injection is optional and that you must apply the Dependency attribute to target class properties if you want property injection of dependent types to occur.
Using the Dependency Attribute with Constructor and Method Parameters
You can also apply the Dependency attribute to the parameters of a constructor or method to specify the named mapping you want the container to use. If you do not specify a named mapping, Unity uses the default (unnamed) mapping. For more details, see Annotating Objects for Constructor Injection and Annotating Objects for Method Call Injection.
Property Injection with Existing Objects
If you use configuration or the RegisterInstance method to register an existing object, property (setter) injection does not take place on that object because it has already been created outside of the influence of the Unity container. However, you can call the BuildUp method of the container and pass it the existing object to force property injection to take place on that object.
Avoiding the Use of Public Properties
To use property injection, you must expose a public property from your class to which you can apply the Dependency attribute. If the only reason you are exposing this property is to implement injection, and you would prefer not to expose it as a public property, you can use method call injection instead. Create an Initialize method for the class that takes the type to resolve as a parameter and apply the InjectionMethod attribute to this method. Unity will resolve the parameter and call the method. Inside the method, you can store a reference to the resolved object for use in your code. For more details, see Annotating Objects for Method Call Injection.
Avoiding Circular References
Dependency injection mechanisms can cause application errors if there are circular references between objects that the container will create. For more details, see Circular References with Dependency Injection.
When to Use Property (Setter) Injection
You should consider using property injection in the following situations:
- When you want to instantiate dependent objects automatically when you instantiate the parent object.
- When you want a simple approach that makes it easy to see in the code what the dependencies are for each class.
- When the parent object requires a large number of constructors that forward to each other, making debugging and maintenance difficult.
- When the parent object constructors require a large number of parameters, especially if they are of similar types and the only way to identify them is by position.
- When you want to make it easier for users to see what settings and objects are available, which is not possible using constructor injection.
- When you want to control which objects are injected by editing the code of the dependent object instead of the parent object or application.
If you are not sure which type of injection to use, the recommendation is that you use constructor injection. This is likely to satisfy almost all general requirements unless you need to perform injection on existing object instances.
Note
You can also configure property injection at design time or run time. For more information, see Configuring Unity.