Design of ObjectBuilder

The construction and disposal of object instances is a common process in most applications, particularly in business applications such as those built using the Enterprise Library. For this reason, the Enterprise Library application blocks take advantage of an underlying sub-system named ObjectBuilder that performs all of the repetitive and necessary tasks for creating object instances, while still providing a high level of flexibility.
ObjectBuilder encapsulates features that simplify the creation of object instances. It can do the following:
  • It can create specific concrete class instances, even when requests are for abstract types.
  • It can return existing object instances when this is appropriate, or always generate new instances.
  • It can create the appropriate objects from factory classes based on configuration data.
  • It can intelligently select the appropriate constructor when a class exposes more than one constructor.
  • It can automatically apply values to public properties and execute methods on the object in response to pre-defined policies.
  • It can respond to attributes declared on the properties and methods, which influence the creation and naming of the new object.
  • It can automatically communicate with objects that support the IBuilderAware interface to indicate that object creation is complete.
  • It can provide a tear-down facility that can remove settings from existing objects by reversing the chain of operations.

ObjectBuilder Architecture

ObjectBuilder uses a pipeline of strategies. With this pipeline, multiple operations can take place as objects are instantiated and prepared for use. This means you can control the order in which the processes take place. It also supports controlled disposal of object instances by executing the appropriate pipeline processes in the reverse order.
ObjectBuilder strategies manage the processes performed on objects during construction and disposal. The ObjectBuilder pipeline is organized into stages, and each stage of the pipeline contains multiple strategies. You can implement your own strategies as a .NET Framework classes with a specific interface.

ObjectBuilder Methods

ObjectBuilder resides in the namespace Microsoft.Practices.ObjectBuilder, and the base class BuilderBase exposes two methods. The BuildUp method has two overloads.

BuildUp(locator, type, id, instance, policies[] );
BuildUp<type>(locator, id, instance, policies[] ); 

The following describes elements in the preceding code:
  • locator. This is a reference to a class that implements the IReadWriteLocator interface; it provides hints as to the location of the object or class. For more information, see "Using a ReadWriteLocator" later in this topic.
  • type. This is the type of object to create.
  • id. This is the identifier to assign to the new object instance.
  • instance. This is an optional reference to an existing object instance on which the pipeline process will act. This allows you to take existing objects and make sure that they are properly prepared for use by passing them through the pipeline. ObjectBuilder applies only the appropriate processes to such object instances.
  • policies[]. This is an array of PolicyList instances that implement transient policies that override the built-in policies. For more information, see "Using a PolicyList" later in this topic.
The TearDown method takes an existing object instance and runs it back through the strategy chain. This process can remove features added to the object during the BuildUp process if you want to re-use the object.
The signature of the TearDown method is shown here.

public TItem TearDown<TItem>(IReadWriteLocator locator, TItem item) 

Using a ReadWriteLocator

ObjectBuilder uses the concept of a lifetime container to store object references, which ensures the correct management of objects and their disposal at the correct times. Locators reference individual objects within the lifetime container. Multiple items in a locator can point to the same object instance. For example, items in a locator can reference it through the class type name, the interfaces it implements, and the object name.
Locators can be read-only or read-write, and the BuildUp method of ObjectBuilder takes an instance of an object that implements the IReadWriteLocator interface.

Using a PolicyList

A PolicyList is a set of policies, each represented by classes that implement the IBuilderPolicy interface, that together influence the way that ObjectBuilder creates an object. Policies can be transient or permanent.
Transient policies are those automatically generated by the strategies in ObjectBuilder or through reflection over the attributes on the methods and properties declared in the class file.
Permanent policies are those you create by implementing the IBuilderPolicy interface. You can pass an array of these class instances to the BuildUp method in ObjectBuilder.

Pipeline Stages

The pipeline in ObjectBuilder consists of the following four stages:
  1. PreCreation. This stage occurs before ObjectBuilder creates a new instance of the object.
  2. Creation. In this stage, ObjectBuilder creates the new object instance.
  3. Initialization. In this stage, ObjectBuilder prepares the object for use. It sets properties on the new object instance and invokes methods.
  4. PostInitialization. This stage occurs just before ObjectBuilder returns the newly created object.
The following table lists the default processes that ObjectBuilder completes at each stage of the pipeline.

Pipeline Stage ObjectBuilder Strategies
PreCreation TypeMappingStrategySingletonStrategyConstructorReflectionStrategy
Creation CreationStrategy
Initialization PropertySetterStrategyPropertyReflectionStrategyMethodReflectionStrategyMethodExecutionStrategy
PostInitialization BuilderAwareStrategy


The application blocks that use ObjectBuilder add specific strategies to the pipeline, and you can add your own strategies if required.

Strategy Types

This section describes the default strategies for ObjectBuilder listed in the preceding table:
  • TypeMappingStrategy. This strategy can set the actual return type for objects. For example, a request for an abstract or interface type IMyObject can automatically force translation into the concrete type MyObject.
  • SingletonStrategy. This strategy specifies whether ObjectBuilder returns a new instance of an object or an existing instance if one is available.
  • ConstructorReflectionStrategy. This strategy inspects the class for attributes declared on constructors, in particular the [InjectionConstructor] attribute, and chooses which to use to construct the object. More details of how parameters in the constructor decorated with the [Dependency] and [CreateNew] attributes influence behavior are described later in this section.
  • CreationStrategy. This strategy instantiates the new object, using either the constructor or the Activator class methods.
  • PropertySetterStrategy. This strategy can set the value of public properties of the new object instance, based on policy.
  • PropertyReflectionStrategy. This strategy inspects the class for attributes on properties and applies these to the new object instance. Properties decorated with the [Dependency] and [CreateNew] attributes cause injection of these values into the new object instance.
  • MethodReflectionStrategy. This strategy inspects the class for attributes on methods that must run during the Initialization stage.
  • MethodExecutionStrategy. This strategy executes methods on the new object instance, depending on policy.
  • BuilderAwareStrategy. This strategy inspects the class to see if it implements the IBuilderAware interface. If it does, ObjectBuilder informs the object when construction is complete and the object is ready for use by raising the OnBuiltUp event. If ObjectBuilder is executing the TearDown method, it raises the OnTearingDown event.
You can derive your own class from the BuilderBase class if you want to create more stages, modify or remove the existing ones, use your own stages, or pre-initialize a builder to suit your requirements. Look at the source file for the builder (Builder.cs) for an example of how to do this.

Attribute-based Dependency Injection

ObjectBuilder supports a general-purpose attribute-based dependency injection. Two of the built-in strategies, ConstructorInjectionStrategy and PropertyInjectionStrategy, provide dependency injection. Both of these strategies support a common set of attributes that you can apply to variables. These attributes are the following:
  • [CreateNew]. This attribute tells the dependency injection system to always create a new one of whatever it is you need. This is helpful for patterns such as Model-View-Controller (MVC) or Model-View-Presenter (MVP), where creating a view automatically generates a new controller/presenter.
  • [Dependency]. This is a general-purpose attribute with four optional parameters:
    • Name. This parameter specifies a named object instead of an unnamed object. If it is omitted, the default setting is null (unnamed).
    • NotPresentBehavior. This parameter specifies what happens if the object you want does not exist. The default value is NotPresentBehavior.CreateNew.
    • CreateType. This parameter specifies the type to be created.
    • SearchMode. When ObjectBuilder needs to find an object to resolve a dependency, it searches in the current locator. The locator can be created with a parent locator which can also be searched. The valid options are
The provision of these parameters on the [Dependency] attribute means that it can satisfy all the following requirements:
  • Find the unnamed X (where X is a type). If it does not exist, throw an exception.
  • Find the unnamed X. If it does not exist, create a new one.
  • Find the unnamed X. If it does not exist, provide a null value instead.
  • Find the X named Y (where Y is a string). If it does not exist, throw an exception.
  • Find the X named Y. If it does not exist, create a new one.
  • Find the X named Y. If it does not exist, provide a null value instead.
For example, the following code always generates an object of type MyCustomObject.

using Microsoft.Practices.ObjectBuilder;

[Dependency(CreateType=typeof(MyCustomObject),
            NotPresentBehavior=NotPresentBehavior.CreateNew)]
public ICustomObject MyCustomObject { set { ... } } 

If the system cannot find an ICustomObject, it creates a new MyCustomObject and registers it with the type of ICustomObject for the next person who needs an ICustomObject. The default setting is null.

Constructor, Property, and Method Injection

Three of the built-in strategies, ConstructorReflectionStrategy, PropertyReflectionStrategy, and MethodReflectionStrategy, use the [Dependency] and [CreateNew] attributes to control their behavior.
The ConstructorReflectionStrategy has two phases. First, it figures out which constructor to use. Second, it figures out how to satisfy those constructor parameters.
The ConstructorReflectionStrategy first looks for any constructor that has the [InjectionConstructor] attribute applied (there can be only one of these) and uses this constructor if found. If there is no decorated constructor but there is only one constructor, it uses that constructor. If there are multiple constructors but none carries the [InjectionConstructor] attribute, the strategy throws an exception.
After selecting the constructor, the strategy determines how to fulfill the requirements of the parameters to the constructor. These may be marked with the [Dependency] and/or [CreateNew] attributes. Any parameter that has no attributes applied is treated as though it has the default [Dependency] attribute (unnamed, NotPresentBehavior= NotPresentBehavior.CreateNew, SearchMode = Up) applied.
The PropertyReflectionStrategy looks for properties with the [Dependency] and [CreateNew] attributes and satisfies them appropriately (they must be public and have setters). It does not do anything with any properties that have no attributes applied on a class.
The MethodReflectionStrategy looks for methods that have the [MethodInjection] attribute applied and that execute during the initialization phase. The parameters of these methods may contain the [CreateNew] and [Dependency] attributes. Any parameter that has no attributes applied is treated as though the default [Dependency] attribute (unnamed, NotPresentBehavior= NotPresentBehavior.CreateNew, SearchMode = Up) is applied.

Last edited Nov 19, 2007 at 9:10 PM by siacomuzzi, version 1

Comments

No comments yet.