Udostępnij za pośrednictwem


Injecting Resolved Types into Other Classes

One of the major advantages provided by dependency injection mechanisms such as Unity is the ability to automatically inject resolved instances of types into other classes at run time. This is the preferred approach, as it provides several advantages over other techniques (for details of these advantages, see Creating and Referencing Enterprise Library Objects.)

Unity supports injection into the parameters of constructors and methods, and to set the value of properties. This means that you can easily inject instances of the Enterprise Library objects and your own components and services into custom business objects and other components. The following sections of this topic provide more information:

  • Using Constructor Injection
  • Using Property (Setter) Injection
  • Using Method Call Injection

Note

Other topics in this section show how you can resolve instances of Enterprise Library objects on demand, and how you can create instances of Enterprise Library objects directly. For more information, see Resolving Instances of Types Using Unity and Creating Application Block Objects Directly.

Using constructor, method, and property injection allows you to inject instances of resolved types not only into the target type (the type you are actually resolving), but it also populates dependencies in all resolved types. The following schematic shows an overview of the process.

Ff664647.b5180262-b347-4a4c-b044-bf7f7756151d(en-us,PandP.50).png

For more detailed information about the dependency injection features of Unity, see Unity Dependency Injection and Interception.

Using Constructor Injection

This example shows how a custom class can depend on a concrete implementation of the Enterprise Library Database class through a parameter in its constructor. The following code shows the custom class.

public class MyNewObject
{
  public MyNewObject(Database defaultDB)
  { 
    // code to use the resolved Database instance here
  }
} 
'Usage
Public Class MyNewObject
  Public Sub New(defaultDB As Database)
    ' code to use the resolved Database instance here
  End Sub
End Class 

When you specify just the type in a constructor parameter, as above, the container will return the default concrete implementation of that type as defined in the Enterprise Library configuration. To specify a named registration when using constructor injection, you add the Dependency attribute to the parameter definition, as shown below.

public class MyNewObject
{
  public MyNewObject([Dependency("CustomerDB")] Database customers)
  { 
    // code to use the resolved Database instance here
  }
} 
'Usage
Public Class MyNewObject
  Public Sub New(<Dependency("CustomerDB")> customers As Database)
    ' code to use the resolved Database instance here
  End Sub
End Class 

You can also define constructor injection in a configuration file or at run time by registering the type in the container. These approaches provide more control over the injection process (including the ability to specify parameter overrides or dependency overrides that set the values of specific parameters), create optional dependencies so that Unity will set the value of a parameter or property to null (C#) or Nothing (Visual Basic) if it cannot resolve the type of the dependency, and specify a lifetime manager that will control the lifetime of the resolved type.

When you instantiate the custom class by resolving it through the container, as shown in the following code, the container will resolve the parameter types and inject the resolved objects into the parameters. For the first example, it will inject a reference to the default Database implementation. For the second example, it will inject the Database defined in configuration with the name CustomerDB. This code assumes that you have saved a reference to the container that holds the Enterprise Library configuration in the variable named container.

MyNewObject myNewInstance = container.Resolve<MyNewObject>();
'Usage
Dim myNewInstance As MyNewObject = container.Resolve(Of MyNewObject)()

For more details about constructor injection, and how it works when you have more than one constructor in a class, see The Unity Configuration Schema, Registering Injected Parameter and Property Values, and Annotating Objects for Constructor Injection in the Unity documentation.

Using Property Injection

Another approach is to take advantage of property setter injection to populate one or more properties of your custom classes at run time. You define a property in the target class and apply the Dependency attribute to it or configure it as a dependency in your configuration 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 MyNewObject that exposes as a property a reference to an instance of an Enterprise Library object that implements the ICacheManager interface.

public class MyNewObject
{
  private ICacheManager theCache;

  [Dependency()]
  public ICacheManager DefaultCache
  {
    get { return theCache; }
    set { theCache = value; }
  }
} 
'Usage
Public Class MyNewObject

  Private theCache As ICacheManager

  <Dependency()> _
  Public Property DefaultCache() As ICacheManager
    Get
      Return theCache
    End Get
    Set(ByVal value As ICacheManager)
      theCache = value
    End Set
  End Property

End Class 

When you apply the Dependency attribute without specifying a name, the container will return the default concrete implementation of that type, as defined in the Enterprise Library configuration. To specify a named registration when using property injection, you include the name as a parameter of the Dependency attribute, as shown below.

public class MyNewObject
{
  private ICacheManager theCache;

  [Dependency("LocalCache")]
  public ICacheManager NamedCache
  {
    get { return theCache; }
    set { theCache = value; }
  }
} 
'Usage
Public Class MyNewObject

  Private theCache As ICacheManager

  <Dependency("LocalCache")> _
  Public Property NamedCache() As ICacheManager
    Get
      Return theCache
    End Get
    Set(ByVal value As ICacheManager)
      theCache = value
    End Set
  End Property

End Class 

You can also define property injection in a configuration file or at run time by registering the type in the container. These approaches provide more control over the injection process, including the ability to create optional dependencies so that Unity will set the value of a parameter or property to null (C#) or Nothing (Visual Basic) if it cannot resolve the type of the dependency; and specify a lifetime manager that will control the lifetime of the resolved type.

When you instantiate the custom class by resolving it through the container, as shown in the following code, the container will populate the property automatically by resolving the class type and name through the Enterprise Library container. For the first example, it will inject a reference to the default CacheManager implementation. For the second example, it will inject the CacheManager defined in configuration with the name LocalCache. This code assumes that you have saved a reference to the default container that holds the Enterprise Library configuration in the variable named container.

MyNewObject myInstance = container.Resolve<MyNewObject>();
Dim myInstance As MyNewObject = container.Resolve(Of MyNewObject)()

For more details about property injection, see The Unity Configuration Schema, Registering Injected Parameter and Property Values, and Annotating Objects for Property (Setter) Injection in the Unity documentation.

Note

Using property setter injection means that you must expose a public property from your class that Unity can populate. In some cases, you may want to resolve objects without using constructor injection and without exposing the resolved object through a public property. In this case, you may choose to use method call injection, as described in the following section.

Using Method Call Injection

Although the two most common types of dependency injection are constructor and property setter injection, there are times when method call injection is a more appropriate technique. While constructor injection is typically the most common technique, it does not work with existing instances of objects. Property injection does work with existing instances, but it means that you must expose a public property. Method call injection provides an alternative approach for automatically resolving objects and obtaining references to them in your class.

The usual approach is to expose a public initialization method that takes as parameters the objects you want to resolve and obtain references to. Unity will populate the parameters and then call the method. As the method executes, you store the resolved types in local variables of your class. You apply the InjectionMethod attribute to the method or configure it as a dependency in your configuration 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 MyNewObject that exposes a method named Initialize that takes as parameters instances of the Enterprise Library CacheManager and CryptographyManager objects.

public class MyNewObject
{
  private CacheManager myCache;
  private CryptographyManager myCrypto;

  [InjectionMethod]
  public void Initialize(CacheManager cache, CryptographyManager crypto) 
  {
    // assign the dependent objects to class-level variables
    myCache = cache;
    myCrypto = crypto;
  }
} 
'Usage
Public Class MyNewObject

  Private myCache As CacheManager
  Private myCrypto As CryptographyManager

  <InjectionMethod()> _
  Public Sub Initialize(cache As CacheManager, crypto As CryptographyManager)
    ' assign the dependent objects to class-level variables
    myCache = cache
    myCrypto = crypto
  End Sub

End Class 

The example above uses the default mappings in the container, so will inject the types defined as the default in the application configuration. To specify the concrete types by name, you apply the Dependency attribute to the parameters exactly as you would when using constructor injection. The following code illustrates this.

public class MyNewObject
{
  private CacheManager myCache;
  private CryptographyManager myCrypto;

  [InjectionMethod]
  public void Initialize([Dependency("DBCache")] CacheManager cache,
                         [Dependency("DPAPI")] CryptographyManager crypto) 
  {
    // assign the dependent objects to class-level variables
    myCache = cache;
    myCrypto = crypto;
  }
} 
'Usage
Public Class MyNewObject

  Private myCache As CacheManager
  Private myCrypto As CryptographyManager

  <InjectionMethod()> _
  Public Sub Initialize(<Dependency("DBCache")> cache As CacheManager, _
                        <Dependency("DPAPI")> crypto As CryptographyManager)
    ' assign the dependent objects to class-level variables
    myCache = cache
    myCrypto = crypto
  End Sub

End Class 

You can also define method call injection in a configuration file or at run time by registering the type in the container. These approaches provide more control over the injection process, including the ability to specify parameter overrides or dependency overrides that set the values of specific parameters; create optional dependencies so that Unity will set the value of a parameter or property to null (C#) or Nothing (Visual Basic) if it cannot resolve the type of the dependency; and specify a lifetime manager that will control the lifetime of the resolved type.

When you instantiate the custom class by resolving it through the container, as shown in the following code, the container will automatically populate the method parameters by resolving the class types and names through the Enterprise Library container, and then call the method.

MyNewObject myInstance = container.Resolve<MyNewObject>();
Dim myInstance As MyNewObject = container.Resolve(Of MyNewObject)()

For more details about method call injection, see The Unity Configuration Schema, Registering Injected Parameter and Property Values, and Annotating Objects for Method Call Injection in the Unity documentation.