Wednesday, December 14, 2005

ObjectBuilder

Updated 1/14/2006 to include definition of MyBuilderContext class

I've started to play with ObjectBuilder (OB) that comes with CAB and EntLib to learn how it works. I’m no expert so take what I’m about to say in that context. What I’m doing is looking at the unit test to figure out how it works. You could also take a look at the CAB and EntLib 2.0 code to get an idea as well. I create a simple sample to get my feet wet. Again I did this as a first try at understanding OB and the code presented here has been stripped down to present the idea. The important things to note is that OB is a framework for building a DI system, so you have to write some code to the DI system in place. In this example the DI sub-system (the poor mans version) is implemented in the MyContextFactory. Also note that my sample does not dispose of the object by running through the build strategy at the end… this is my laziness.

This is the main program file. I want to create an instance of MyForm as a singleton without using new and also inject the necessary object needed by MyForm. In this example I also wanted to test constructor injection, method injection and property injection. Method injection is a very interesting idea fro doing initialization after construction… neat.

Program.cs


using System;
using System.Collections.Generic;
using System.Windows.Forms;


namespace ObjectBuilderApp
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

MyForm form = MyBuilderFactory<MyForm>.BuildSingletonObject( "Main Form" );
Application.Run(form);
}
}
}


This is the MyForm class that represents the form. Note I did not show the designer code here. It requires a number of object that are injected.

MyForm.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Practices.ObjectBuilder;

namespace ObjectBuilderApp
{
public partial class MyForm : Form
{
private Customer _customer;
private Foo _foo;

// Constructor Injection
[InjectionConstructor()]
public MyForm(Customer customer) : this()
{
this._customer = customer;
}


// Setter Injection
[Dependency( SearchMode = SearchMode.Local, CreateType = typeof(Foo), NotPresentBehavior = NotPresentBehavior.CreateNew)]
public Foo Foo
{
set
{
this._foo = value;
}
}

// Method Injection
[InjectionMethod()]
public void Display([Dependency(CreateType = typeof(Foo), NotPresentBehavior = NotPresentBehavior.CreateNew)] Foo foo)
{
System.Diagnostics.Trace.WriteLine(foo.Name);
}

[InjectionMethod()]
public void Display2([Dependency(CreateType = typeof(Foo), NotPresentBehavior = NotPresentBehavior.CreateNew)] Foo foo)
{
System.Diagnostics.Trace.WriteLine(foo.Name);
}

[InjectionMethod()]
public void Display3([Dependency(CreateType = typeof(Foo), NotPresentBehavior = NotPresentBehavior.CreateNew)] Foo foo)
{
System.Diagnostics.Trace.WriteLine(foo.Name);
}

public MyForm()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(this._customer._foo.Name);
}
}
}


This is the MyContextFactory class. This is a static class that allows for the creation of an object based on the Object Builder (OB) framework. In some ways this class is my DI subsystem (yes not a very good version).

MyContextFactory.cs

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.ObjectBuilder;

namespace ObjectBuilderApp
{
public class MyBuilderFactory<T> where T : class
{
public static T BuildSingletonObject( string name )
{
MyBuilderContext ctx = new MyBuilderContext();

//ctx.InnerChain.Add(new SingletonStrategy());
ctx.InnerChain.Add(new CreationStrategy());

// enables method injection
ctx.InnerChain.Add(new MethodReflectionStrategy());
ctx.InnerChain.Add(new MethodExecutionStrategy());

// enables property njection
ctx.InnerChain.Add(new PropertyReflectionStrategy());
ctx.InnerChain.Add(new PropertySetterStrategy());

ctx.Policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());

ctx.Policies.Set<ISingletonPolicy>(new SingletonPolicy(true), typeof(MyForm), null);

return ctx.HeadOfChain.BuildUp(ctx, typeof(T), null, name) as T;
}
}
}



This Customer class is the Customer class that gets injected into the MyForm class, but itself also needs another object Foo to be injected.

Customer.cs

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.ObjectBuilder;
using System.Windows.Forms;

namespace ObjectBuilderApp
{
public class Customer
{
public Foo _foo;

// Constructor Injection
[InjectionConstructor]
public Customer([CreateNew] Foo foo)
{
this._foo = foo;
}

// Method Injection
[InjectionMethod]
public void Display([Dependency(Name="MyFoo", CreateType = typeof(Foo), NotPresentBehavior = NotPresentBehavior.CreateNew)] Foo foo)
{
System.Diagnostics.Trace.WriteLine(foo.Name);
}
}
}



The Foo class is just a nother class that gets used by the Customer class. This class does not use any kind of injection.

Foo.cs
using System;

using System.Collections.Generic;
using System.Text;

namespace ObjectBuilderApp
{
public class Foo
{
string _name;

public string Name
{
get
{
if (this._name == null)
return "Norm";
else
return this._name;
}
set
{
this._name = value;
}
}
}
}



MyBuilderContext.cs

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.ObjectBuilder;

namespace ObjectBuilderApp
{
public class MyBuilderContext : BuilderContext
{
public IReadWriteLocator InnerLocator;
public BuilderStrategyChain InnerChain = new BuilderStrategyChain();
public PolicyList InnerPolicies = new PolicyList();
public LifetimeContainer lifetimeContainer = new LifetimeContainer();

public MyBuilderContext()
: this(new Locator())
{
}

public MyBuilderContext(IReadWriteLocator locator)
{
InnerLocator = locator;
SetLocator(InnerLocator);
StrategyChain = InnerChain;
SetPolicies(InnerPolicies);

if (!Locator.Contains(typeof(ILifetimeContainer)))
Locator.Add(typeof(ILifetimeContainer), lifetimeContainer);
}
}
}