This post was published on an earlier personal blog, no longer online. ‘Caraway’ grew up and became Autofac, still an active and evolving open-source project. The project is introduced in the previous post, and the next post shows the beginnings of Autofac’s lifetime model.

The newest version of Caraway introduces some significant API changes that streamline component registration. Inspired by Ninject’s fluent interface, the new ContainerBuilder replaces the plethora of Register() methods with some simple alternatives that let the compiler do more generic-argument type inference and provide more details of the component’s implementation type to the container (improving registration-time detection of type errors.)

There are still some finer points to be worked out and with the level of API change I suppose that beta has become a misnomer.

Builder Syntax

Previously, component registration was done directly through overloads of IInjectionContainer.Register(). In 0.4, IInjectionContainer and InjectionContainer have been replaced by IContainer, Container and ContainerBuilder. IContainer contains Resolve() methods and Container adds RegisterComponent(IComponentRegistration) to this. ContainerBuilder provides a friendlier syntax for creating component registrations:

var builder = new ContainerBuilder();

// Register a type that is itself exposed as a service
builder.Register<A>();

// Register an instance that exposes a service interface
var b = new B();
builder.Register(b).As<IB>();

// Create a container with the registrations
var container = builder.Build();
var a = container.ResolveOptional<A>();

Property initialisation

A neat new C# 3.0 feature allows you to initialise properties on newly-created instances using a syntax like:

new Class1() { Property1 = value1, ... }

This is exactly equivalent to:

var o1 = new Class1();
o1.Property1 = value1;
...

When designing components a best practice requires that mandatory dependencies are provided through the constructor, and optional dependencies are provided through properties. When using delegates/lambdas to create components, mandatory dependencies, like the dependency of C on A below, are suited to the Resolve() method which will throw an exception if the service cannot be provided. Caraway 0.4 introduces a new method - IContainer.ResolveOptional() - that can be used with the new property initialisation syntax to match the semantics of optional dependencies by returning null rather than throwing an exception when a dependency cannot be satisfied:

// Register an activation delegate with an optional
// dependency set through a property:
builder.Register(ctr => new C(ctr.Resolve<A>()){ MyB = ctr.ResolveOptional<IB>() });

This makes the delegate syntax a truly first-class way to register components - both mandatory and optional dependencies can be succinctly expressed, and debugging is easier because the Invoke() boundary doesn’t need to be crossed.

Comments

Posted by Nate Kohari October 02, 2007 00:22

Cool stuff. I’m glad you found Ninject’s fluent interface inspiring. :)

Nice work on Caraway, by the way. Looks like it has a lot of potential. Gotta love simple answers to complex problems!

Posted by Nicholas Blumhardt October 03, 2007 01:01

Thanks, Nate! There’s some really exciting stuff in Ninject - it’s an awesome piece of software you’ve built. I’m glad to see it taking off!