Using Container Hierarchies
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 Enterprise Library information can be found at the Enterprise Library site. |
The Unity Application Block supports nested containers, allowing you to build container hierarchies. Nesting containers provides two useful capabilities for managing dependency injection and object lifetime. They allow you to do the following:
- Control the scope and lifetime of singleton object instances
- Register different mappings for specific types
Controlling Object Scope and Lifetime
When the container creates singleton objects, it manages the lifetime of these singletons. They remain in scope until you (or the garbage collector) dispose the container. At this point, it disposes the registered singleton instances it contains. In addition, if you dispose the parent container in a nested container hierarchy, it automatically disposes all child containers and the registered singletons they contain.
Therefore, if you require two separate sets of such objects that must have different lifetimes, you can use hierarchical containers to store and manage each set. Register instances that you want to be able to dispose separately in one or more child containers that you can dispose without disposing the parent container.
The following code demonstrates the use of a child container to manage the lifetime of specific singleton instances while maintaining the singleton instances in the parent container.
// Create parent container
IUnityContainer parentCtr = new UnityContainer();
// Register type in parent container
parentCtr.RegisterType<MyParentObject>(new ContainerControlledLifetimeManager());
// Create nested child container in parent container
IUnityContainer childCtr = parentCtr.CreateChildContainer();
// Register type in child container
childCtr.RegisterType<MyChildObject>(new ContainerControlledLifetimeManager());
// Create instance of type stored in parent container
MyParentObject parentObj = parentCtr.Resolve<MyParentObject>();
// Create instance of type stored in child container
MyChildObject childObj = childCtr.Resolve<MyChildObject>();
// ... can use both generated objects here ...
// Dispose child container
childCtr.Dispose();
// ... can use only object in parent container here ...
// Dispose parent container
parentCtr.Dispose();
'Usage
' Create parent container
Dim parentCtr As IUnityContainer = New UnityContainer()
' Register type in parent container
parentCtr.RegisterType(Of MyParentObject)(New ContainerControlledLifetimeManager())
' Create nested child container in parent container
Dim childCtr As IUnityContainer = parentCtr.CreateChildContainer()
' Register type in child container
childCtr.RegisterType(Of MyChildObject)(New ContainerControlledLifetimeManager())
' Create instance of type stored in parent container
Dim parentObj As MyParentObject = parentCtr.Resolve(Of MyParentObject)()
' Create instance of type stored in child container
Dim childObj As MyChildObject = childCtr.Resolve(Of MyChildObject)()
' ... can use both generated objects here ...
' Dispose child container
childCtr.Dispose()
' ... can use only object in parent container here ...
' Dispose parent container
parentCtr.Dispose()
Note
You can also specify the lifetime of objects by using the LifetimeManager parameter when you register types or existing objects with the container. For details of how to use the LifetimeManager parameter, see System Design When Using a Dependency Injection Container and Registering Existing Object Instances. For details of how to create custom lifetime managers, see Creating Lifetime Managers.
Registering Different Mappings for Specific Types
You can use nested containers when you have slightly different dependency injection requirements for specific objects but want to provide a "fallback" facility for objects that implement a specific interface, or are of a specific type. For example, you may have a general requirement for objects that implement the IMyObject interface to map to the type MyStandardObject. However, in specific parts of the application code, you may want the IMyObject interface to map to the type MySpecialObject.
In this case, you can register the general mapping in the parent container and register the specific case in a child container. Then, when you want to obtain an instance of the object, you call the Resolve method on the appropriate container. If you call the method on the child container, it returns an object of type MySpecialObject. If you call the method on the parent container, it returns an object of type MyStandardObject.
However, the advantage with nested containers is that, if the child container cannot locate a mapping for the requested interface or type, it passes the request to its parent container; and onwards through the hierarchy until it reaches the "root" or "base" container. Therefore, for objects not mapped in the child container, the mapping in the parent container (or in an ancestor container where there are more than two levels in the hierarchy) will define the object type returned.
The following code shows how you can implement the preceding scenario.
// Create parent container
IUnityContainer parentCtr = new UnityContainer();
// Register two mappings for types in parent container
parentCtr.RegisterType<IMyObject, MyStandardObject>();
parentCtr.RegisterType<IMyOtherObject, MyOtherObject>();
// Create nested child container in parent container
IUnityContainer childCtr = parentCtr.CreateChildContainer();
// Register mapping for specific type in child container
childCtr.RegisterType<IMyObject, MySpecialObject>();
// Now retrieve instances of the mapped objects using the child container.
// Using the interface as the type for the returned objects means that it
// does not matter which container returns the actual object.
// This code returns an object of type MySpecialObject using the mapping
// registered in the child container:
IMyObject specialObject = childCtr.Resolve<IMyObject>();
// This code returns an object of type MyOtherObject using the mapping
// registered in the parent container because there is no mapping in
// the child container for this type:
IMyOtherObject otherObject = childCtr.Resolve<IMyOtherObject>();
// Now retrieve instance of the standard object using the parent container.
// This code returns an object of type MyStandardObject using the mapping
// registered in the parent container:
IMyObject standardObject = parentCtr.Resolve<IMyObject>();
// Dispose parent container and child container
parentCtr.Dispose();
'Usage
' Create parent container
Dim parentCtr As IUnityContainer = New UnityContainer()
' Register two mappings for types in parent container
parentCtr.RegisterType(Of IMyObject, MyStandardObject)()
parentCtr.RegisterType(Of IMyOtherObject, MyOtherObject)()
' Create nested child container in parent container
Dim childCtr As IUnityContainer = parentCtr.CreateChildContainer()
' Register mapping for specific type in child container
childCtr.RegisterType(Of IMyObject, MySpecialObject)()
' Now retrieve instances of the mapped objects using the child container.
' Using the interface as the type for the returned objects means that it
' does not matter which container returns the actual object.
' This code returns an object of type MySpecialObject using the mapping
' registered in the child container:
Dim specialObject As IMyObject = childCtr.Resolve(Of IMyObject)()
' This code returns an object of type MyOtherObject using the mapping
' registered in the parent container because there is no mapping in
' the child container for this type:
Dim otherObject As IMyOtherObject = childCtr.Resolve(Of IMyOtherObject)()
' Now retrieve instance of the standard object using the parent container.
' This code returns an object of type MyStandardObject using the mapping
' registered in the parent container:
Dim standardObject As IMyObject = parentCtr.Resolve(Of IMyObject)()
' Dispose parent container and child container
parentCtr.Dispose()