Demystifying the ObjectBuilder
In my last post, I gave an introduction to ObjectBuilder. In this post, I take ObjectBuilder apart and talk about all of the hairy details.
ObjectBuilder is used in the Enterprise Library, the CAB, and the Mobile framework MS just released. If you have to extend any of the above frameworks/libraries in a non-trivial way, you are going to need to understand what is going on under the covers. Under the covers of the above frameworks/libraries is ObjectBuilder--the dependency injection framework.
Unfortunately, there is not any documentation for the ObjectBuilder, so learning is a real nightmare. I was able to break it by going over the unittests that ship with the source code.
Fundamental Classes in Object Builder
Strategy and Policies - OB is based upon policies and strategies. Strategies are chained (i.e. OB implements the Chain of Responsability pattern on strategies) and get registered for a build stage. Strategies use policies to figure out how to build an object. Policies are registered with OB for types. A policy is defined for types (objects in OB are defined by the type and ID).
Locator - locators in OB are used to find registered objects. When an object is created, it gets registered with the locator (see CreationStrategy.RegisterObject).
LifetimeContainer - objects managed by the object builder can have a lifetime associated with them. The thing that determines how long an object stays around is the container that the object is associated with. LifetimeContainers in OB, maintain a list of objects. When the container is disposed off, the objects in it are also disposed.
BuilderContext- an object that defines the context for the build-up and tear-down of an object. BuilderContext holds the strategies, policies and locator for the given build-up or tear-down. It also provides a method to iterate the chain of strategies (see IBuilderContext and BuilderContext).
OB By Example
/**********Create A Singleton*************/
public void CreateASingleton()
{
// we need a locator, a strategy chain, and a list of policies.
Locator locator = new Locator();
BuilderStrategyChain strategyChain = new BuilderStrategyChain();
PolicyList policies = new PolicyList();
// in order to build a singleton, we have to
// have a SingletonStrategy. The singleton strategy
// in turn uses a SingletonPolicy.
// add a SingletonStrategy to the strategy chain
strategyChain.Add(new SingletonStrategy());
// add a CreationStrategy to the strategy chain
strategyChain.Add(new CreationStrategy());
// SingletonStrategy requires a SingletonPolicy
policies.Set<ISingletonPolicy>(new SingletonPolicy(true), typeof(MyObject), null);
// we also need a creation policy
policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());
// in order to make singletons, we need a lifetime container in the locator
locator.Add(typeof(ILifetimeContainer), new LifetimeContainer());
// create the object
BuilderContext cxt = new BuilderContext(strategyChain, locator, policies);
// in order to properly track singletons, we have to give the instance an ID.
object myObj = strategyChain.Head.BuildUp(cxt, typeof(MyObject), "MyObject_Singleton", null);
object myObj2 = strategyChain.Head.BuildUp(cxt, typeof(MyObject), "MyObject_Singleton", null);
if (myObj == myObj2)
{
// Got singleton in myObj2
int J = 0;
}
}
The example above demonstrates creating singleton objects with the OB. Most of the work simply sets up using the OB. For example, in order to create an object, we need to have a build context. A build context requires a locator, a strategy chain, and a policy list. There are several pieces that enable singletons, however. For example, utimately a strategy is the thing that will create an object in OB. Strategies rely on policies to determine how to create an object. To create a singleton, we have to have a SingletonStrategy in the strategy chain. The singleton strategy looks for a SingletonPolicy, registered for the object being created. Recall that policies are setup for types.
There are a few design aspects of OB that we have to understand. OB uses something called a Locator. A locator knows how to find registered objects. Locators can be nested (i.e., a locator can have a parent). Locators make use of something called a LifetimeContainer. LifetimeContainer puts a boundary around the lifetime of a created object. When a locator is asked to find an object it can look in the current locator and/or it's parent locator (if one exists).
It's important to know that when searching for singletons, OB looks only at the current locator--the parent is not searched. The SingletonStrategy class in OB is shown below for reinforcement of this.
public class SingletonStrategy : BuilderStrategy
{
public override object BuildUp(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
DependencyResolutionLocatorKey key = new DependencyResolutionLocatorKey(typeToBuild, idToBuild);
if (context.Locator != null && context.Locator.Contains(key, SearchMode.Local))
{
TraceBuildUp(context, typeToBuild, idToBuild, "");
return context.Locator.Get(key);
}
return base.BuildUp(context, typeToBuild, existing, idToBuild);
}
}
As shown, the SingletonStrategy checks to see if the build context has a locator,and then asks the locator to find the object using a SearchMode.Local. This tells the locator not to look in the parent locator for the object. This has obvious usage implications--if you don't create your singletons with the correct locator, then you'll end up breaking the singleton (TODO: more on this.).
Also note that we have put a CreationStrategy in the chain of strategies for our singleton object. The SingletonStrategy ensures that once we have an object, that object is returned on subseqent build-up requests. The CreationStrategy is needed to build-up the object the first time. Since the CreationStrategy is the strategy that builds the object, this strategy also registers the object with the locator/container so that it can be pulled out the next time. We can see this by looking at the CreationStrategy.
public class CreationStrategy : BuilderStrategy
{
public override object BuildUp(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
if (existing != null)
BuildUpExistingObject(context, typeToBuild, existing, idToBuild);
else
existing = BuildUpNewObject(context, typeToBuild, existing, idToBuild);
return base.BuildUp(context, typeToBuild, existing, idToBuild);
}
private void BuildUpExistingObject(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
RegisterObject(context, typeToBuild, existing, idToBuild);
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.SerializationFormatter)]
private object BuildUpNewObject(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
ICreationPolicy policy = context.Policies.Get<ICreationPolicy>(typeToBuild, idToBuild);
if (policy == null)
{
if (idToBuild == null)
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
Properties.Resources.MissingPolicyUnnamed, typeToBuild));
else
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
Properties.Resources.MissingPolicyNamed, typeToBuild, idToBuild));
}
try
{
existing = FormatterServices.GetSafeUninitializedObject(typeToBuild);
}
catch (MemberAccessException exception)
{
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Properties.Resources.CannotCreateInstanceOfType, typeToBuild), exception);
}
RegisterObject(context, typeToBuild, existing, idToBuild);
InitializeObject(context, existing, idToBuild, policy);
return existing;
}
private void RegisterObject(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
if (context.Locator != null)
{
ILifetimeContainer lifetime = context.Locator.Get<ILifetimeContainer>(typeof(ILifetimeContainer), SearchMode.Local);
if (lifetime != null)
{
ISingletonPolicy singletonPolicy = context.Policies.Get<ISingletonPolicy>(typeToBuild, idToBuild);
if (singletonPolicy != null && singletonPolicy.IsSingleton)
{
context.Locator.Add(new DependencyResolutionLocatorKey(typeToBuild, idToBuild), existing);
lifetime.Add(existing);
if (TraceEnabled(context))
TraceBuildUp(context, typeToBuild, idToBuild, Properties.Resources.SingletonRegistered);
}
}
}
}
//...more methods ....
}
As shown above, the BuildUp method checks to see if it has to build-up a new object or an existing one. In our case, we are building up an object for the firsttime. In this case, the BuildUpNewObject method is called. This method looks on the build context for a ICreationPolicy for the required object. If it doesn't find one, it throws an exception--in other words, you have to have a policy registered for the object that tells OB how to create the object. In our case, we are using the DefaultCreationPolicy. If there is a ICreationPolicy, then the method builds a bare-bones object (one that is not initialized) using
existing = FormatterServices.GetSafeUninitializedObject(typeToBuild);
and then calls RegisterObject(). This is where the singleton magic happens. As you can see from the code snippet above, the CreationStrategy looks for a lifetime container on the local locator and if one exists, it looks for a singleton policy registered for the required object. If it finds the singleton policy, it adds a key for the newly build object to the lifetime container.
Thus, we can conclude that in order to create singleton objects with OB, we need to have a SingletonStrategy and a SingletonPolicy. There are two aspects to creating a singleton:
- When creating an object, you have to register it.
- When creating an object, you have to check to see if one already exists.
The singleton policy, ensures that the object gets registered with the local locator's lifetime container and the singleton strategy ensures that the registered object gets returned on subsequent build-up operations.
OB is a glorified object factory and DI framework. To support DI, OB ships with some strategies and policies. Lets investigate these now. [TODO: Correct this intro into DI via Properties]
Injecting into Properties
DI in OB is achived at build-up. When you ask OB to build-up an object, OB runs a chain of strategies. The idea is to inject dependencies into objects at build-up. To do that, you put a strategy object, an object that knows how to do the proper injection, into the chain of strategies. One of the strategies that knows how to inject dependencies is the PropertySetterStrategy. An example will help.
public void PropertyInjectionExample()
{
Locator locator = new Locator();
LifetimeContainer container = new LifetimeContainer();
locator.Add(typeof(ILifetimeContainer), container);
// strategies ...
BuilderStrategyChain chain = new BuilderStrategyChain();
chain.Add(new CreationStrategy());
chain.Add(new PropertySetterStrategy());
// policies...
PolicyList policies = new PolicyList();
// Property setter policy for MyDAOObject's ConnectionString
PropertySetterPolicy psp = new PropertySetterPolicy();
// add a property for the ConnectionString property
psp.Properties.Add("ConnectionString", new PropertySetterInfo("ConnectionString",new ValueParameter<string>("the connection string value would be here")));
policies.Set<IPropertySetterPolicy>(psp, typeof(MyDAOObject), null);
policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());
// create build conetxt...
BuilderContext cxt = new BuilderContext(chain, locator, policies);
// build the object
MyDAOObject obj = chain.Head.BuildUp(cxt, typeof(MyDAOObject), null, null) as MyDAOObject;
}
class MyDAOObject
{
private string connectionString;
public string ConnectionString
{
get
{
return connectionString;
}
set
{
connectionString = value;
}
}
public MyDAOObject():this(null) { }
public MyDAOObject(string conStr)
{
connectionString = conStr;
}
}
In our introduction, we mentioned that DI is achieved by injecting dependencies into properties or via constructors. The PropertySetterStrategy, as the name suggests, injects dependencies using properties. In order to get properties injected into your objects, you have to add a PropertySetterStrategy instance to the strategy chain (as shown above). The BuildUp method of this strategy is shown below.
public override object BuildUp(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
if (existing != null)
InjectProperties(context, existing, idToBuild);
return base.BuildUp(context, typeToBuild, existing, idToBuild);
}
As you can see, the BuildUp method ensures that the object has been created and then it calls the InjectProperties method. Note the implication here--you have to make sure you have a strategy that creates the object ahead of the PropertySetterStrategy in the strategy chain. Otherwise, the strategy is effectively skipped because the base class's BuildUp is called to call the next strategy in the chain. Now lets have a look at the InjectProperties method (see below).
private void InjectProperties(IBuilderContext context, object obj, string id)
{
if (obj == null)
return;
Type type = obj.GetType();
IPropertySetterPolicy policy = context.Policies.Get<IPropertySetterPolicy>(type, id);
if (policy == null)
return;
foreach (IPropertySetterInfo propSetterInfo in policy.Properties.Values)
{
PropertyInfo propInfo = propSetterInfo.SelectProperty(context, type, id);
if (propInfo != null)
{
if (propInfo.CanWrite)
{
object value = propSetterInfo.GetValue(context, type, id, propInfo);
if( value != null )
Guard.TypeIsAssignableFromType(propInfo.PropertyType, value.GetType(), obj.GetType());
if (TraceEnabled(context))
TraceBuildUp(context, type, id, Properties.Resources.CallingProperty, propInfo.Name, propInfo.PropertyType.Name);
propInfo.SetValue(obj, value, null);
}
else
{
throw new ArgumentException(String.Format(
CultureInfo.CurrentCulture,
Properties.Resources.CannotInjectReadOnlyProperty,
type, propInfo.Name));
}
}
}
}
The InjectProperties method checks to see if an object exists and then looks for an implementation of IPropertySetterPolicy registered for the type. If it finds an IPropertySetterPolicy for the type, it iterates over the list properties that need to be injected. The list of properties that need to be injected and the values that need to be injected into these properties are defined by IPropertySetterPolicy.
public interface IPropertySetterPolicy : IBuilderPolicy
{
Dictionary<string, IPropertySetterInfo> Properties { get; }
}
Every property that needs to be injected has to have an entry into this dictionary. Every property has a string key and an IPropertySetterInfo instance that defines the property and the value for that property. Therefore, in our example above, when we create the PropertySetterPolicy for MyObject, we added the following for the ConnectionString property.
psp.Properties.Add("ConnectionString", new PropertySetterInfo("ConnectionString",new ValueParameter<string>("the connection string value would be here")));
The Add method adds an entry with the key "ConnectionString" and a new PropertySetterInfo for the ConnectionString property. If we go back to the InjectProperties method, we can see that the method iterates over the list of IPropertySetterInfo objects. For each property configured for injection, it calls the SelectProperty method on the IPropertySetterInfo object. The default implementation of this interface (PropertySetterInfo) looks at the type to see if it has a property with given name and if it finds one, it returns a PropertyInfo for that type. Note that when we created the PropertySetterInfo object for the property, we gave it the name of the property along with the ValueParameter instance in the constructor of PropertySetterInfo. The IPropertySetterInfo interface defines the SelectProperty method, mentioned above, and the GetValue method (see below). The GetValue method returns the value that has to be injected into the property.
public interface IPropertySetterInfo
{
object GetValue(IBuilderContext context, Type type, string id, PropertyInfo propInfo);
PropertyInfo SelectProperty(IBuilderContext context, Type type, string id);
}
After the InjectProperty method gets the PropertyInfo object for the property, it checks to see if the property can be written to (i.e., if it has a setter), and then calls the GetValue method on the IPropertySetterInfo implementation. The default implementation of this interface calls the GetValue method on the IParameter. In our example, we passed in an ValueParameter instance, which is an implementation of IParameter that stores the value in the class and returns it when needed. Once the value for the property is obtained, the InjectProperties method checks to make sure that the value of the property can be assigned to the property and then it calls PropertyInfo.SetValue.
That's the details on DI via properties. With this much detail, it is easy to lose focus on the big picture, so lets understand the design of this aspect of the OB. The figure below dipicts the design of DI via properties in OB.

As shown, there are really three core interfaces involved in the design, IPropertySetterPolicy, IPropertySetterStrategy, and IPropertySetterInfo. The strategy class looks for a registered IPropertySetterPolicy at build-up for a given type. If the policy is registered for the type, the strategy iterates the properties that require injection. Every injection property is represented by an IPropertySetterInfo. IPropertySetterInfo encapsulates two things about the property: what the property is and how to get a value for the property. OB provides an implementation of this interface, PropertySetterInfo, that operates on an IParameter abstraction (see PropertySetterInfo class below).
public class PropertySetterInfo : IPropertySetterInfo
{
string name = null;
PropertyInfo prop = null;
IParameter value = null;
public PropertySetterInfo(string name, IParameter value)
{
this.name = name;
this.value = value;
}
public PropertySetterInfo(PropertyInfo propInfo, IParameter value)
{
this.prop = propInfo;
this.value = value;
}
public PropertyInfo SelectProperty(IBuilderContext context, Type type, string id)
{
if (prop != null)
return prop;
return type.GetProperty(name);
}
public object GetValue(IBuilderContext context, Type type, string id, PropertyInfo propInfo)
{
return value.GetValue(context);
}
}
As shown, at a minimum, you need to know two things to get a value injected into a property: 1) the name of the property and 2) how to get the value for the property. IParameter provides an abstraction to obtaining, and customizing, how the PropertySetterStrategy obtains the value to assign to the property. In our example earlier, for example, we used a ValueParameter extension that stored the value of the ConnectionString in the class and returned it when the strategy asked for it. The design of DI via properties also shows that OB provides a number of other IParameter extensions. For example, the LookupParameter implementation of IParameter looks in the build-context to find the value of the parameter. Here is an example using LookupParameter.
public void LookupParameterExample()
{
Locator locator = new Locator();
LifetimeContainer container = new LifetimeContainer();
locator.Add(typeof(ILifetimeContainer), container);
BuilderStrategyChain chain = new BuilderStrategyChain();
PolicyList policies = new PolicyList();
// put the connection string in the context
locator.Add("ConnectionString", "connection string goes here");
// add strategies
chain.Add(new CreationStrategy());
chain.Add(new PropertySetterStrategy());
// add policies
policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());
PropertySetterPolicy psp = new PropertySetterPolicy();
// configure the property value to be pulled from the
// build context
psp.Properties.Add("CS",new PropertySetterInfo("ConnectionString",new LookupParameter("ConnectionString")));
// set the policy for the type MyDAOObject
policies.Set<IPropertySetterPolicy>(psp, typeof(MyDAOObject), null);
// create build context
BuilderContext cxt = new BuilderContext(chain, locator, policies);
// build-up object
MyDAOObject obj = chain.Head.BuildUp(cxt, typeof(MyDAOObject), null, null) as MyDAOObject;
}
First notice that we add an item to the locator named "ConnectionString". Second, when we add a property registration to the PropertySetterPolicy, we use a LookupParameter. Finally, when we create the LookupParameter, we give the key to use when looking up the parameter's value.
Now lets talk about DI via constructors.
Injecting into Constructors
Similar to how we inject into properties, we can inject into constructors.
Locator locator = new Locator();
// add connection string to the locator
locator.Add("ConnectionString", "connection string goes here...");
LifetimeContainer container = new LifetimeContainer();
locator.Add(typeof(ILifetimeContainer), container);
BuilderStrategyChain chain = new BuilderStrategyChain();
PolicyList policies = new PolicyList();
// add strategies
chain.Add(new CreationStrategy());
// add policies
ConstructorPolicy cp = new ConstructorPolicy();
// use a lookup parameter to get the connection string from
// the local locator
cp.AddParameter(new LookupParameter("ConnectionString"));
policies.Set<ICreationPolicy>(cp, typeof(MyDAOObject), null);
BuilderContext cxt = new BuilderContext(chain, locator, policies);
// buildup
MyDAOObject obj = chain.Head.BuildUp(cxt, typeof(MyDAOObject), null, null) as MyDAOObject;
The goal of this excercise is to inject the connection string into MyDAOObject via the constructor at build-up. Recall from our definition of MyDAOObject above that the class defined two constructors: a zero argument constructor and one that took a string parameter (i.e. the connection string). Our objective is to have the connection string picked up from the locator and injected into the object when the object is build-up. To do that, we first do the usual stuff. We create a locator, lifetime container, a strategy chain and a policy list. We add strategies and set policies and then do build-up. The difference, as always, is in what strategies and policies we're using. One way to have injection occur, for constructors, is to use a CreationStrategy combined with a ConstructorPolicy. The ConstructorPolicy class is an ICreationPolicy that determines the constructor to call based on the parameters added to its policy. In our scenario, for example, we've added the connection string parameter using a LookupParameter. Recall that when the CreationStrategy.BuildUp is called, it gets the ICreationPolicy for the type and the calls SelectConstructor. When this method is called on the ConstructorPolicy, it reflects on the type and finds the constructor that matches the list of parameters added to its parameter list (see SelectConstructor below).
public ConstructorInfo SelectConstructor(IBuilderContext context, Type type, string id)
{
if (constructor != null)
return constructor;
List<Type> types = new List<Type>();
foreach (IParameter parm in parameters)
types.Add(parm.GetParameterType(context));
return type.GetConstructor(types.ToArray());
}
After the correct constructor is selected, CreationStrategy then asks the ICreationPolicy to get the parameters for the constructor. Similarly, ConstructorPolicy then looks at the list of parameters added to it, and creates an object array of values passed for the parameters. The method is shown below.
public object[] GetParameters(IBuilderContext context, Type type, string id, ConstructorInfo constructor)
{
List<object> results = new List<object>();
foreach (IParameter parm in parameters)
results.Add(parm.GetValue(context));
return results.ToArray();
}
Recall that LookupParameter.GetValue looks on the locator to get the value.
That's the fundementals of injected dependencies via properties and constructor parameters. In the next section, we'll extend this discussion and talk about DI using the Dependency attribute. As you'll see, you can decorate your objects properties and constructor parameters with [Dependency] and have them injected.
Injection into Methods by Method Execution
Thus far you've seen that OB can inject dependencies via properties and constructors. OB can also inject depdencies into methods by executing methods at build-up. The example below demonstrates this.
public class MyDAOObject
{
private string username, password;
...
public void Credentials(string userName, string passWord)
{
this.username = userName;
this.password = passWord;
}
}
public void ExecuteMethodExample()
{
Locator locator = new Locator();
LifetimeContainer container = new LifetimeContainer();
locator.Add(typeof(ILifetimeContainer), container);
BuilderStrategyChain chain = new BuilderStrategyChain();
PolicyList policies = new PolicyList();
// add strategies
chain.Add(new CreationStrategy());
chain.Add(new MethodExecutionStrategy());
// add policies
policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());
// add a method policy for MyDAOObject
MethodPolicy mp = new MethodPolicy();
IMethodCallInfo methodInfo = new MethodCallInfo("Credentials", new object[] {"myUserName","myPassword" });
mp.Methods.Add("credentials", methodInfo);
policies.Set<IMethodPolicy>(mp, typeof(MyDAOObject), null);
// create context
BuilderContext cxt = new BuilderContext(chain, locator, policies);
// build up
MyDAOObject obj = chain.Head.BuildUp(cxt, typeof(MyDAOObject), null, null) as MyDAOObject;
}
As you can see, we've added another method, Credentials, to our MyDAOObject class. The method takes two string parameters: the username and password. The purpose of the example is to build an instance of MyDAOObject and then execute the Credentials method on it. To do that, we ask use the MethodExecutionStrategy along with a IMethodPolicy implementation.
The example, by now, is self explanatory--add a MethodExecutionStrategy after the CreationStrategy and then setup a IMethodPolicy to register the Credentials method, with the specific parameters, on the MyDAOObject and then call BuildUp.
This is probably a good time to stop and make a point about OB's build-up process. If you think of dependency injection with properties and constructors and then compare that to dependency injection via method execution, you can see that there is a difference in semantics. This leads to several questions.
Why would you ever want to inject dependencies via methods? Isn't enough to just inject via properties and/or constructors? It seems to make more sense if you go with properties/constructors. For example, it makes perfect sense to inject the dependencies of an object when you create the object (via constructors). Setting properties on the object can be considered an extension of constructing an object, so its okay to inject dependencies after you call the constructor. But injecting the dependencies of an object by calling a method on it, seems a bit dirty. Why? Is it because an object may not have public properties or a visible constructor? For example, we may have a static class that only defines a static method. The answer to why OB supports DI via method execution has to do with the intended use of the build-up process.
Objects in OB can be build-up more than once. In fact, objects in OB are build-up repeatedly. This doesn't mean that objects are "re-instantiated". It just means that objects are run through the chain of strategies again and again. If you look at one of the definitions of IBuilder.BuildUp, we can see hints of this.
object BuildUp(IReadWriteLocator locator, Type typeToBuild, string idToBuild, object existing,
params PolicyList[] transientPolicies);
As shown, one of the parameters to BuildUp is an existing (created) instance of the object that needs to be build-up. If an object already exists, then OB runs the stratetgy chain on the existing object. This enables some interesting solutions to be built on top of OB. The CAB, for example, has built several interesting solutions on the principal that we can execute methods as part of the build-up process. CAB has implemented a publish-subscribe pattern and a command pattern on top of OB. The fact that OB can execute methods, and injection dependencies doing so, enables these features to be built. We'll talk about CAB's extensions later. For now, know that if it were not for these facilities in OB, then OB would simply be an object factory.
Metadata Driven OB
The examples we've covered thus far demonstrate the basics of OB. The real-world applications and application blocks built using OB make use of the metadata-driven facilities provided by OB, which build upon the strategies we've talked about thus far. Metadata-driven OB is driven by decorating objects with attributes. When you ask OB for an object, OB inspects the metadata on the object, hooks up policies, injects dependencies and then returns an instance. All of this happens at runtime when you build-up an object. At the heart of all of this is a strategy base class named ReflectionStrategy, which is extended by the three reflection based classes PropertyReflectionStrategy, ConstructorReflectionStrategy, and MethodReflectionStrategy, and a host of attribute classes. Namely, CreateNew, Dependency, InjectionConstructor, InjectionMethod, and InjectionParameter (see figure below).

Lets get started with an example using ConstructorReflectionStrategy and [Dependency].
public class MyDAOObject2
{
private string connectionString = null;
public MyDAOObject2([Dependency(Name = "ConnectionString", SearchMode = SearchMode.Local, NotPresentBehavior = NotPresentBehavior.Throw)]string connectionString)
{
this.connectionString = connectionString;
}
}
public void ConstructorInjectionExample()
{
Locator locator = new Locator();
LifetimeContainer container = new LifetimeContainer();
locator.Add(typeof(ILifetimeContainer), container);
// add connection string to the context
locator.Add(new DependencyResolutionLocatorKey(typeof(string), "ConnectionString"), "connection string goes here");
BuilderStrategyChain chain = new BuilderStrategyChain();
PolicyList policies = new PolicyList();
// add strategies
chain.Add(new ConstructorReflectionStrategy());
chain.Add(new CreationStrategy());
// add policies
policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());
// create context
BuilderContext cxt = new BuilderContext(chain, locator, policies);
MyDAOObject2 obj2 = chain.Head.BuildUp(cxt, typeof(MyDAOObject2), null, null) as MyDAOObject2;
}
As shown, we have a class named MyDAOObject2, which has a constructor that takes the connection string. The interesting thing here is that we have decorated the constructor parameter with the Dependency attribute. This effectively tells OB that the class has a dependency on the defined parameter and to inject the parameter at build-up. Note that we have supplied some values to several properties defined on the Dependency attribute class for the connection string parameter. Specifically, we have supplied the Name, SearchMode and NotPresentBehavior property values. When OB has to inject the dependency, it looks at these values to determine where to look for the value and what to do if the value cannot be found. In our example, we are telling OB to look in the current locator for the connection string value and if it cannot find the value, then throw an exception.
As usual, we create a locator, a strategy chain and a policy list. Note that we add the connection string to the locator using DependencyResolutionLocatorKey. In order for OB to interpret the [Dependency], we put an instance of ConstructorReflectionStrategy into the strategy chain. As always, strategies use polices, and so we set the default creation policy to DefaultCreationPolicy. When we call BuildUp, OB resolves the dependency and creates the object correctly. So where is the magic happening? Where does OB pick the Dependency attribute and at what point, and how is the value for the dependency obtained?
Most of the magic happens in the base class of ConstructorReflectionStrategy: ReflectionStrategy. The essentials of ReflectionStrategy is shown below.
public abstract class ReflectionStrategy<TMemberInfo> : BuilderStrategy
{
protected abstract IEnumerable<IReflectionMemberInfo<TMemberInfo>> GetMembers(IBuilderContext context, Type typeToBuild, object existing, string idToBuild);
protected abstract void AddParametersToPolicy(IBuilderContext context, Type typeToBuild, string idToBuild,
IReflectionMemberInfo<TMemberInfo> member, IEnumerable<IParameter> parameters);
protected abstract bool MemberRequiresProcessing(IReflectionMemberInfo<TMemberInfo> member);
public override object BuildUp(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
foreach (IReflectionMemberInfo<TMemberInfo> member in GetMembers(context, typeToBuild, existing, idToBuild))
{
if (MemberRequiresProcessing(member))
{
IEnumerable<IParameter> parameters = GenerateIParametersFromParameterInfos(member.GetParameters());
AddParametersToPolicy(context, typeToBuild, idToBuild, member, parameters);
}
}
return base.BuildUp(context, typeToBuild, existing, idToBuild);
}
...
}
ReflectionStrategy is the base class for metadata-driven injection processors. ReflectionStrategy defines three protected abstract methods that are used to define the template for consuming attributes on properties, constructors, and methods.
The BuildUp method in ReflectionStrategy defines the template for consuming injection attributes. Derived classes don't implement BuildUp--their job is to just provide implementation for th abstract methods. The BuildUp method calls the GetMembers abstract method to get the list of members that have to be considered for injection attributes and then iterate over each member, asking the derived class if the member needs to be processed. If so, then policies are added to the context for the injection parameters.
Lets now take a deeper look at the extension of ReflectionStrategy in turn. We'll start with ConstructorReflectionStrategy.
Dependency Injection using ConstructorReflectionStrategy
In our ConstructorReflectionStrategy example, we decorated the constructor parameter of MyDAOObject2 with [Dependency]. Lets see how the dependency is resolved and injected into the constructor.
As mentioned earlier, the process of resolving injection parameters is templatized by ReflectionStrategy.BuildUp. Thus, we have to look at the implementation of the three abstract methods in ConstructorReflectionStrategy to see what happens when injection attributes are placed on constructor parameters. ConstructorReflectionStrategy is shown below.
public class ConstructorReflectionStrategy : ReflectionStrategy<ConstructorInfo>
{
protected override IEnumerable<IReflectionMemberInfo<ConstructorInfo>> GetMembers(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
List<IReflectionMemberInfo<ConstructorInfo>> result = new List<IReflectionMemberInfo<ConstructorInfo>>();
ICreationPolicy existingPolicy = context.Policies.Get<ICreationPolicy>(typeToBuild, idToBuild);
if (existing == null && (existingPolicy == null || existingPolicy is DefaultCreationPolicy))
{
ConstructorInfo injectionCtor = null;
ConstructorInfo[] ctors = typeToBuild.GetConstructors();
if (ctors.Length == 1)
injectionCtor = ctors[0];
else
{
foreach (ConstructorInfo ctor in ctors)
{
if (Attribute.IsDefined(ctor, typeof(InjectionConstructorAttribute)))
{
// Multiple decorated constructors aren't valid
if (injectionCtor != null)
throw new InvalidAttributeException();
injectionCtor = ctor;
}
}
}
if (injectionCtor != null)
result.Add(new ReflectionMemberInfo<ConstructorInfo>(injectionCtor));
}
return result;
}
protected override void AddParametersToPolicy(IBuilderContext context, Type typeToBuild, string idToBuild, IReflectionMemberInfo<ConstructorInfo> member, IEnumerable<IParameter> parameters)
{
ConstructorPolicy policy = new ConstructorPolicy();
foreach (IParameter parameter in parameters)
policy.AddParameter(parameter);
context.Policies.Set<ICreationPolicy>(policy, typeToBuild, idToBuild);
}
protected override bool MemberRequiresProcessing(IReflectionMemberInfo<ConstructorInfo> member)
{
return true;
}
}
Recall that GetMembers has to return an IEnumerable for the list of members, for the type, that need injection attribute processing. ConstructorReflectionStrategy has to return the constructor that has [InjectionConstructor] defined. This attribute is used to tell ConstructorReflectionStrategy, which constructor to use for attribute-based dependency injection, if you have more than one constructor defined. Notice that we didn't put this attribute on our constructor definition of MyDAOObject2, which means that [InjectionConstructor] is optional if only one constructor has injection attributes. The GetMembers method for ConstructorReflectionStrategy checks to see if only one constructor is defined, and if so, it takes that constructor as the injection constructor. If more than one constructor is defined, it looks for the [InjectionConstructor]. Note that multiple constructors decorated with [InjectionConstructor] is invalid.
So ConstructorReflectionStrategy.GetMembers, returns a ReflectionMemberInfo for the [InjectionConstructor]. ReflectionMemberInfo, is a wrapper for items that need injection attribute processing. In the case of ConstructorReflectionStrategy, this is a wrapper around the constructor that has [InjectionConstructor]. We'll see a bit later, how ReflectionMemberInfo also wraps properties and methods.
After ReflectionStrategy get the list of members that need injection attribute processing, the next thing it has to do is add appropriate policies to the context for each parameter. Recall from our earlier discussion where we injected a dependency using ConstructorPolicy. Using ConstructorPolicy and a ValueParameter, we manually established where and how to resolve the dependency. Using ConstructorReflectionStrategy and [Dependecy], effectively takes this manual step our of the picture because ConstructorReflectionStrategy creates a ConstructorPolicy and adds an IParameter for each parameter for you. Note that AddParametersToPolicy iterates over the list of parameters and then adds that to the ConstructorPolicy. After which, it sets the ICreationPolicy, for the type, to the created constructor policy. Since this is a ConstructorReflectionStrategy, the type that needs to be build has not been constructed when this code executes. Which means that if the client is using the defualt creation strategy (CreationStrategy), and if the default creation policy (DefaultCreationPolicy) was set (which is the case in our ConstructorReflectionStrategy example above), that policy gets overriden by the newly created ConstructorPolicy. So, when CreationStrategy.InitializeObject runs, the correct constructor is selected and the proper values are passed into the constructor.
Now lets see how this is done with properties are decorated with attributes.
Dependency Injection using PropertyReflectionStrategy
PropertyReflectionStrategy extends ReflectionStrategy to support injection attributes on properties. The example below demonstrates using this extension.
public class MyDAOObject3
{
private string connectionString;
[Dependency(Name = "ConnectionString", SearchMode = SearchMode.Local,
NotPresentBehavior = NotPresentBehavior.Throw)]
public string ConnectionString
{
get
{
return connectionString;
}
set
{
connectionString = value;
}
}
}
public void PropertyReflectionStrategyExample()
{
Locator locator = new Locator();
LifetimeContainer container = new LifetimeContainer();
locator.Add(typeof(ILifetimeContainer), container);
// add connection string to locator
locator.Add(new DependencyResolutionLocatorKey(typeof(string), "ConnectionString"), "connection string goes here");
BuilderStrategyChain chain = new BuilderStrategyChain();
PolicyList policies = new PolicyList();
// add strategies
chain.Add(new PropertyReflectionStrategy());
chain.Add(new CreationStrategy());
chain.Add(new PropertySetterStrategy());
// add policies
policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());
// create context
BuilderContext cxt = new BuilderContext(chain, locator, policies);
// do buildUp
MyDAOObject3 obj = chain.Head.BuildUp(cxt, typeof(MyDAOObject3), null, null) as MyDAOObject3;
}
In the code snippet above, we've created a class named MyDAOObject3 which has a single property named ConnectionString. This property is decorated with the same [Dependency] that was previously set on the constructor of MyDAOObject2. The obvious idea is to have OB inject this propety at build-up. To have OB interpret the metadata on the ConnectionString property, we have to add a few strategies to the strategy chain. In the last section, all we had was a ConstructorReflectionStrategy. Here, we see two new strategies: PropertyReflectionStrategy and PropertySetterStrategy. Note that the usual CreationStrategy sit in between these two. Why? In the section we had a ConstructorReflectionStrategy precede CreationStrategy because the strategy needed to resolve which constructor to call, prior to instantiating the object. With properties, however, we have to wait for the object to be instantiated prior to calling properties. Thus, we use the PropertyReflectionStrategy to [TODO] and the PropertySetterStrategy to assign property values.
As before, the magic lies in the PropertyReflectionStrategy implementations of the three abstract methods defined in ReflectionStrategy (see below).
public class PropertyReflectionStrategy : ReflectionStrategy<PropertyInfo>
{
protected override IEnumerable<IReflectionMemberInfo<PropertyInfo>> GetMembers(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
foreach (PropertyInfo propInfo in typeToBuild.GetProperties())
yield return new PropertyReflectionMemberInfo(propInfo);
}
protected override void AddParametersToPolicy(IBuilderContext context, Type typeToBuild, string idToBuild, IReflectionMemberInfo<PropertyInfo> member, IEnumerable<IParameter> parameters)
{
PropertySetterPolicy result = context.Policies.Get<IPropertySetterPolicy>(typeToBuild, idToBuild) as PropertySetterPolicy;
if (result == null)
{
result = new PropertySetterPolicy();
context.Policies.Set<IPropertySetterPolicy>(result, typeToBuild, idToBuild);
}
foreach (IParameter parameter in parameters)
if (!result.Properties.ContainsKey(member.Name))
result.Properties.Add(member.Name, new PropertySetterInfo(member.MemberInfo, parameter));
}
protected override bool MemberRequiresProcessing(IReflectionMemberInfo<PropertyInfo> member)
{
return (member.GetCustomAttributes(typeof(ParameterAttribute), true).Length > 0);
}
...
}
The GetMembers method is now returning an IEnumerable for the list of properties on the type. Recall from ReflectionStrategy.BuildUp that as each member is iterated, a call is made to MemberRequiresProcessing to see if that property needs to be processed. Since GetMembers returns all of the properties, MemberRequiresProcessing is used to ensure that the property being considered has at least one custom property which extends [Parameter]. From the defintion of MyDAOObject3, we know that ConnectionString is decorated with [Dependeny], and [Dependency]does extend [Parameter].
After the property is determined to be processable, ReflectionStrategy.BuildUp calls AddParametersToPolicy to add the property to the policy. In ConstructorReflectionStrategy.AddParametersToPolicy we saw that a new ConstructorPolicy was created for the constructor and the parameters for the constructor were added to that policy and the policy was set on the context for the type. Here, the method is looking for the appropriate policy to be on the context. Why? Recall that ConstructorReflectionStrategy enforced that only one constructor could have the [InjectionConstructor] decoration. Here, more than one property can have an extension of [Parameter] and because you have one policy for a given policy interface, for a type, we can create the policy ahead of time and set it prior to build-up. Note that if the PropertySetterPolicy is not on the context, which is our case, the method creates one and adds it to the context.
After all of the properties have been preprocessed, the object is created, and then PropertySetterStrategy is executed to do the actual injection of values into the properties.
Dependency Injection using MethodReflectionStrategy
MethodReflectionStrategy is also an extension of ReflectionStrategy. This extension strategy is used to support calling methods which have been docorated with an [InjectionMethod] and have [Dependency] parameters. The code snippet below demonstrates this.
public class MyDAOObject3
{
private string connectionString;
private string username, password;
[Dependency(Name = "ConnectionString", SearchMode = SearchMode.Local,
NotPresentBehavior = NotPresentBehavior.Throw)]
public string ConnectionString
{
get
{
return connectionString;
}
set
{
connectionString = value;
}
}
[InjectionMethod]
public void Credentials([Dependency(Name = "DBUserName", SearchMode = SearchMode.Local,
NotPresentBehavior = NotPresentBehavior.Throw)]string userName,
[Dependency(Name = "DBPassword", SearchMode = SearchMode.Local,
NotPresentBehavior = NotPresentBehavior.Throw)]string password)
{
this.username = userName;
this.password = password;
}
}
public void MethodReflectionStrategyExample()
{
Locator locator = new Locator();
LifetimeContainer container = new LifetimeContainer();
locator.Add(typeof(ILifetimeContainer), container);
// add username and password to the locator
locator.Add(new DependencyResolutionLocatorKey(typeof(string), "DBUserName"), "sa");
locator.Add(new DependencyResolutionLocatorKey(typeof(string), "DBPassword"), "fairoza");
BuilderStrategyChain chain = new BuilderStrategyChain();
PolicyList policies = new PolicyList();
// add strategies
chain.Add(new MethodReflectionStrategy());
chain.Add(new CreationStrategy());
chain.Add(new MethodExecutionStrategy());
// add policies
policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());
// create context and buildup
BuilderContext cxt = new BuilderContext(chain, locator, policies);
MyDAOObject3 obj = chain.Head.BuildUp(cxt, typeof(MyDAOObject3), null, null) as MyDAOObject3;
}
You can see that we've added a method to MyDAOObject3 which is decorated with [InjectionMethod]. You can also see that the two parameters to the method are decorated with the [Dependency]. As far as build-up goes, the pattern looks very similar to our previous example--we have two method related strategies sandwiching the CreationStrategy. MethodReflectionStrategy is responsible for identifying the methods on the type that have the [InjectionMethod] decoration (or a derived class of InjectionMethod). MethodExecutionStrategy is responsible for executing the methods with proper values for the method parameters. MethodReflectionStrategy is shown below (we've already discussed MethodExecutionStrategy).
public class MethodReflectionStrategy : ReflectionStrategy<MethodInfo>
{
protected override IEnumerable<IReflectionMemberInfo<MethodInfo>> GetMembers(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
foreach (MethodInfo method in typeToBuild.GetMethods())
yield return new ReflectionMemberInfo<MethodInfo>(method);
}
protected override void AddParametersToPolicy(IBuilderContext context, Type typeToBuild, string idToBuild, IReflectionMemberInfo<MethodInfo> member, IEnumerable<IParameter> parameters)
{
MethodPolicy result = context.Policies.Get<IMethodPolicy>(typeToBuild, idToBuild) as MethodPolicy;
if (result == null)
{
result = new MethodPolicy();
context.Policies.Set<IMethodPolicy>(result, typeToBuild, idToBuild);
}