ObjectBuilder Can Inject to UserControls As Well

This is a followup to my previous post on integrating ObjectBuilder and ASP.NET. As I was playing around with the solution I hit on the fact that I was only injecting at the Page level. As ASP.NET is a component model, you can end up with custom User Controls that would need injected properties as well. There is a relatively simple, if not entirely obvious way to do that as well.

Building on the previous example, you can hook into the lifecycle of a page that you are injecting. You can not access the controls directly in the PreRequestHandlerExecute of the IHttpModule because they have not been instantiated yet. Instead, you can create a callback event handler for the Page.InitComplete event and inject properties at that point.


void InjectProperties(object sender, EventArgs e)
{
IHttpHandler h = app.Context.CurrentHandler;
if (h is DefaultHttpHandler)
return;
chain.Head.BuildUp(builderContext, h.GetType(), h, null);
if (h is Page)
{
// Register a page lifecycle event handler to inject
// user controls on the page itself
page = (Page) h;
page.InitComplete += InjectControls;
}
}

private void InjectControls(object sender, EventArgs e)
{
InjectControls(page);
if (null != page.Form)
InjectControls(page.Form);
}

private void InjectControls(Control mainControl)
{
if (mainControl.Controls != null && mainControl.Controls.Count > 0)
{
foreach (Control c in mainControl.Controls)
{
if (c is UserControl)
{
chain.Head.BuildUp(builderContext, c.GetType(), c, null);
InjectControls(c);
}
}
}
}

As you see with this example, you need to recursively inject the objects into all of the controls. That’s in case there are any nested controls that might need injecting. The other thing to notice is that the controls in the top-level Page doe not contain all of the controls that are also declared in a Form on the page, so you need to handle both of those paths.

Hopefully this will get you further along the path to being able to do dependency injection in your ASP.NET application.

Integrating ObjectBuilder with ASP.NET

ObjectBuilder is a .NET framework made for building Inversion of Control or Dependency Injection containers. Unlike Spring or Pico, ObjectBuilder is not a full DI framework, instead it’s a framework for building DI solutions. Yes, that’s incredibly weird to me too.

Why Use Object Builder?

Why would you use ObjectBuilder instead of a fully baked DI solution? In the .NET world it seems like if it’s not built by Microsoft then it’s not on the table. People really are looking for the “garden path”. So in part it’s really a psychological thing. On the other hand the Microsoft Application Blocks and Enterprise Library are built using ObjectBuilder. So, if you are already using some of those solutions, then you already have a dependency on ObjectBuilder. It is natural to try to control the number of dependencies that a project relies upon. In this case, you have a simple solution that just requires a bit of custom code.

In addition to the fact that it’s basically a roll-your-own DI framework, the other downside of ObjectBuilder is that the documentation is non-existent. It’s said ‘Under construction…’ sine July of 2006, so don’t get your hopes up if you don’t want to look at the API and read the source.

Wire Together Services

If you are going to build a service you could do property based injection. What this means is that in your service layer all of the dependencies are passed into a service via property setters. This keeps the code clean and makes changing the implementation of a dependency very easy. If you have a hardcoded constructor for your dependency in a class then making this kind of change will be harder. It also makes Unit Testing very easy because you can mock out dependencies and isolate the layers of your code.


public class SomeService
{
private SomeDAO someDao;
[Dependency]
public SomeDAO SomeDAO
{
get { return someDao; }
set { someDao = value; }
}

public void Save(SomeObject o)
{
if (o.IsValid)
SomeDAO.Save(o);
}
}

ASP.NET

Most of the examples you can find on the web dealing with ObjectBuilder are about how to use ObjectBuilder as a ServiceBroker where you instantiate a service type object in a view.


public partial class SomePage : System.Web.UI.Page
{
private SomeService someService;
protected void Page_Load(object sender, EventArgs e)
{
Builder builder = NewBuilder();
someService = builder.BuildUp(null, null, null);
}

private Builder NewBuilder()
{
// Create a Builder
}
}

While that’s ok, I think it’s a pretty limiting way to do things. Once you get to any sort of complex object construction, you are going to have to create another class to encapsulate all of the policies and strategies for building objects. The other issue is that using the Services in UI code is very different than compositing the services themselves. It also stands in stark contrast to the clean implementation of the Service layer.

I want to make my pages look more like my Service layer.


public partial class SomePage : System.Web.UI.Page
{
private SomeService someService;
protected void Page_Load(object sender, EventArgs e)
{
}

[Dependency]
public SomeService SomeService()
{
get { return someService; }
set { someService = value; }
}
}

IHttpModules to the Rescue

Page lifecycles are handled by the ASP.NET worker processes so there is no way to construct your own pages and do the Dependency Injection. I immediately went to the idea of a filter (which is how this is done in the Java world). The filter concept in ASP.NET is implemented as an IHttpModule.

The module should do 2 main things:

  • Construct and manage the DI container
  • Inject Properties into the Page object that is going to handle the request

Construct a series of ObjectBuilder classes to create your DI container.

Locator locator = new Locator();
ILifetimeContainer container = new LifetimeContainer();

// Setup the strategy for how objects can be created
BuilderStrategyChain chain = new BuilderStrategyChain();
chain.Add(new CreationStrategy());
chain.Add(new PropertyReflectionStrategy());
chain.Add(new PropertySetterStrategy());
locator.Add(typeof(ILifetimeContainer), container);

// Create a context to build an object
BuilderContext builderContext = new BuilderContext(chain, locator, null);
builderContext.Policies.SetDefault(new DefaultCreationPolicy());

You can access the current Page that will handle the request in an IHttpModule using:

HttpApplication app;
app.Context.CurrentHandler; // The Page handler

Now to tie it all together we create an IHttpModule that will filter each request and wire up our Pages with their dependencies. IHttpModules are configured to respond to callback events related to the Life Cycle of a request. In this case we need wire up our Pages after the PostMapRequestHandler because the Page is created prior to this. I set this up on the PreRequestHandlerExecute because everything is setup at this point and it is right before the Page methods are called.


///

/// ObjectBuilderModule handles PropertyBased Injection for ASP.NET Forms.
///

public class ObjectBuilderModule : IHttpModule
{
private HttpApplication app;
private readonly Locator locator = new Locator();
private readonly ILifetimeContainer container = new LifetimeContainer();
private readonly BuilderStrategyChain chain = new BuilderStrategyChain();
private readonly BuilderContext builderContext;
public ObjectBuilderModule()
{
chain.Add(new CreationStrategy());
chain.Add(new PropertyReflectionStrategy());
chain.Add(new PropertySetterStrategy());
locator.Add(typeof(ILifetimeContainer), container);
builderContext = new BuilderContext(chain, locator, null);
builderContext.Policies.SetDefault(new DefaultCreationPolicy());
}

public void Init(HttpApplication context)
{
app = context;
// PreRequestHandler so that everything is setup including the Session, etc
app.PreRequestHandlerExecute += InjectProperties;
}

void InjectProperties(object sender, EventArgs e)
{
IHttpHandler h = app.Context.CurrentHandler;
if (h is DefaultHttpHandler)
return;
chain.Head.BuildUp(builderContext, h.GetType(), h, null);
}

public void Dispose()
{
app.PostMapRequestHandler -= InjectProperties;
}
}

Conclusion

Hopefully this shows you that you can create a powerful, transparent solution for doing Dependency Injection with ASP.NET. This isn’t necessarily a complete solution. We could implement many other things like Singleton management for various service classes for example. Now all you have to do is extend it for your application’s own needs.