Partager via


Annotating Objects for Method Call Injection

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

The latest Unity Application Block information can be found at the Unity Application Block site.

The Unity Application Block supports dependency injection specified 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 with these instances.

Typical Goals

In this scenario, you use an attribute that is applied to one or more methods of a class to define the dependency injection requirements of that class.

Solution

To perform injection of dependent classes into objects you create through the Unity container, you can apply attributes to the classes that contain these dependencies. For method call injection, you apply the InjectionMethod attribute to the method declarations of a class. The Unity container will force the target object (the object you specify in a Resolve method call) to create an instance of the dependent class and then call the target method. If required, your code in the method can save this instance by assigning it to a class-level variable.

Method call injection is a form of optional injection of dependent objects, provided developers use the Unity container to generate the target object. Unity instantiates dependent objects defined in parameters of methods that carry the InjectionMethod attribute within the scope of the target object. Then it calls the attributed method of the target object before returning the object to the caller. You must apply the InjectionMethod attribute in the target class to initiate method call injection.

For more information, see Notes on Using Method Call Injection.

To use method call injection to create dependent objects for a class

  1. Define a method in the target class and apply the InjectionMethod attribute to it to indicate that any types defined in parameters of the method are dependencies of the class. The following code demonstrates the most common scenario, saving the dependent object instance in a class-level variable, for a class named MyObject that exposes a method named Initialize that takes as a parameter a reference an instance of another class named SomeOtherObject (not defined in this code).

    public class MyObject
    {
    
      public SomeOtherObject dependentObject;
    
      [InjectionMethod]
      public void Initialize(SomeOtherObject dep) 
      {
        // assign the dependent object to a class-level variable
        dependentObject = dep;
      }
    
    } 
    
    'Usage
    Public Class MyObject
    
      Public dependentObject As SomeOtherObject
    
      <InjectionMethod()> _
      Public Sub Initialize(dep As SomeOtherObject)
        ' assign the dependent object to a class-level variable
        dependentObject = dep
      End Sub
    
    End Class 
    
  2. In your run-time code, use the Resolve method of the container to create an instance of the target class. The Unity container will instantiate the dependent concrete class defined in the attributed method, inject it into the target class, and execute the method. For example, the following code shows how you can instantiate the example target class named MyObject containing an attributed method that has a dependency on a class named SomeOtherObject and then reference the injected object.

    IUnityContainer uContainer = new UnityContainer();
    MyObject myInstance = uContainer.Resolve<MyObject>();
    
    // access the dependent object
    myInstance.dependentObject.SomeProperty = "Some value";
    
    'Usage
    Dim uContainer As IUnityContainer = New UnityContainer()
    Dim myInstance As MyObject = uContainer.Resolve(Of MyObject)()
    
    ' access the dependent object
    myInstance.dependentObject.SomeProperty = "Some value"
    
  3. In addition to using concrete types for the dependencies in target object methods, you can use interfaces or base class types and then register mappings in the Unity container to translate these types into the appropriate concrete types. Define a method in the target class that takes as parameters interfaces or base types. For example, the following code shows a target class named MyObject containing a method named Initialize that takes as parameters an object named interfaceObj that implements the interface named IMyInterface and an object named baseObj that inherits from the class MyBaseClass, respectively.

    public class MyObject
    {
    
      public IMyInterface depObjectA;
      public MyBaseClass depObjectB;
    
      [InjectionMethod]
      public void Initialize(IMyInterface interfaceObj, MyBaseClass baseObj) 
      {
        depObjectA = interfaceObj;
        depObjectB = baseObj;
      }
    
    } 
    
    'Usage
    Public Class MyObject
    
      Public depObjectA As IMyInterface
      Public depObjectB As MyBaseClass
    
      <InjectionMethod()> _
      Public Sub Initialize(interfaceObj As IMyInterface, baseObj As MyBaseClass)
        depObjectA = interfaceObj
        depObjectB = baseObj
      End Sub
    
    End Class 
    
  4. 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 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 an attributed method that has 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 public variables containing the dependencies
    IMyInterface depObjA = myInstance.depObjectA;
    MyBaseClass depObjB = myInstance.depObjectB;
    
    'Usage
    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 public variables containing the dependencies
    Dim depObjA As IMyInterface = myInstance.depObjectA
    Dim depObjB As MyBaseClass = myInstance.depObjectA
    

Notes on Using Method Call Injection

The following notes will help you to get the most benefit from using method call injection with the Unity Application Block.

Method Call Injection with Existing Objects

If you use the RegisterInstance method to register an existing object, method call 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 method call injection to take place on that object.

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 Method Call Injection

You should consider using method call injection in the following situations:

  • You want to instantiate dependent objects automatically when your instantiate the parent object.
  • You want a simple approach that makes it easy to see in the code what the dependencies are for each class.
  • The parent object requires a large number of constructors that forward to each other, making debugging and maintenance difficult.
  • 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.
  • You want to hide the dependent objects by not exposing them as properties.
  • 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.

Note

You can also apply method injection at run time using the configuration API of the Unity container. For more information, see Configuring Containers at Run Time.

More Information

For more information about the techniques discussed in this scenario, see the following topics: