Lightweight Adaptation – Coming Soon

The type-to-type mapping of an IoC container obscures the fact that in reality, IoC configuration describes object graphs.

Perhaps this is why it is sometimes difficult to reason about how component instances will come together at runtime?

The problem dealt with in this article fits this description – a simple object graph that is unintuitive to build with a typical container.

Back to the Gang of Four…

The classic “Gang of Four”-style Adapter pattern ‘adapts the interface of one class to another’.
Common scenarios where adapter-like structures appear are, for example:

  • where a wrapper is needed in order to work efficiently with an underlying abstraction;
  • between different representations of the same thing, e.g. the endless variations on ILog; or,
  • between corresponding elements in different logical models

We’ll use a fairly broad definition of the pattern, in the context of an image editing application.

one-to-one

A ToolbarButton has an ICommand that is invoked when the button is clicked. ToolbarButton is an adapter for ICommand that allows the command to be invoked from the user interface.

Here we’ve attached an instance of ToolbarButton to an instance of SaveCommand, which implements ICommand. The classes are:

public interface ICommand
{
    void Execute();
}

public class SaveCommand : ICommand
{
    public void Execute()
    {
        // Save the current image
    }
}

public class ToolbarButton
{
    ICommand _command;
    public ToolbarButton(ICommand command)
    {
        _command = command;
    }
    public void Click()
    {
        _command.Execute();
    }
}

So… from an IoC perspective, what is interesting about this example?

Adapting Multiple Implementations

An application has more than one kind of command. An image editor may have Save, Open and a whole host of other commands:

PaintDotNETToolbar
But, even though all of the command implementations are the different, the widget representing them on the user interface is implemented by the same component.

To bring the example together let’s add an EditorWindow that accepts all of the toolbar buttons as an enumerable dependency.

public class EditorWindow
{
    public EditorWindow(IEnumerable<ToolbarButton> toolbarButtons)
    {
        // Left to the reader’s imagination
    }
}

Our intention here is that for each ICommand in the container, a ToolbarButton will be created to wrap it, and all of these will be passed along to the EditorWindow via the IEnumerable<T> relationship type .

These might be registered with Autofac in the following way:

var builder = new ContainerBuilder();
builder.RegisterType<SaveCommand>().As<ICommand>();
builder.RegisterType<OpenCommand>().As<ICommand>();
builder.RegisterType<ToolbarButton>();
builder.RegisterType<EditorWindow>();
using (var container = builder.Build())
{
    var window = container.Resolve<EditorWindow>();
    window.Show();
}

Yet, there is something wrong. The static structure of our code is correct, but as I lamented earlier, the object graph isn’t what we expect.

The problem is that, as far as the container is concerned, there is only one ToolbarButton component. This will be initialised with whatever happens to be the default implementation of ICommand. Autofac’s last-in-wins policy means that OpenCommand will be used as the default implementation of ICommand, and SaveCommand will be ignored.

nonadapted

This happens because the container builds object graphs top-down; first it looks for ToolbarButton, then it looks for an ICommand to satisfy its dependencies.

Registering Adapters

What we’d really like is to create multiple ToolbarButtons, each attached to a different underlying ICommand implementation.

adapters

To configure this, Autofac 2.2 essentially lets us switch the composition of ToolbarButton from top-down to bottom-up. First we find all of the ICommand implementations, and then we construct a ToolbarButton for each.

Configuration of the container is the same as before, except we change:

builder.RegisterType<ToolbarButton>();

to:

builder.RegisterAdapter<ICommand, ToolbarButton>(cmd => new ToolbarButton(cmd));

The RegisterAdapter() method takes two types as parameters: the service to adapt from, and the component type to adapt to.

Autowiring isn’t supported for the adapter component in this scenario (yet), so we include a lambda expression describing how the adapter is constructed given one of the adapted instances.

Overloads of RegisterAdapter() exist for passing in parameters and an IComponentContext from which the adapter’s other dependencies can be resolved if necessary.

Aside: @joshuamck suggested an alternative syntax that I’d also considered, along the lines of builder.RegisterType<ToolbarButton>().Adapting<ICommand>(). I think this is more in line with the intent of Autofac’s builder syntax, so depending on how the implementation goes we might see this in the 2.2 release version.

Composing with Metadata

In the example, commands can be given metadata to allow the command name to be displayed on the button.

First the commands are given names:

builder.RegisterType<SaveCommand>()
    .As<ICommand>()
    .WithMetadata("Name", "Save File");
builder.RegisterType<OpenCommand>()
    .As<ICommand>()
    .WithMetadata("Name", "Open File");

Then, the name parameter is added to the ToolbarButton constructor and the metadata is consumed:

builder.RegisterAdapter<Meta<ICommand>, ToolbarButton>(cmd =>
    new ToolbarButton(cmd.Value, (string)cmd.Metadata["Name"]));

Adapters, like other relationship types in Autofac, compose nicely with each other as the use of Meta<T> shows.

Wrapping Up*

*Excuse this terrible pun.

Lightweight adapters are a nice little helper coming in Autofac 2.2. While these scenarios don’t arise every day, when they do, container support is very convenient.

Download an example (including an Autofac 2.2 preview build) here.

Autofac 2.1 on Talking Shop Down Under

Richard Banks was kind enough to interview me on Episode 8 of Talking Shop Down Under.

If you’re interested in some of the ideas behind the new Autofac 2.1 release, be sure to check out the podcast!

Introducing Autofac 2.1 RTW

After nearly two years of experimentation, design and development, Autofac’s second major release is here!

Autofac 2.1 is still the IoC container you know and love, but reorganised so that Autofac 1.4′s strengths — especially in providing a low-friction developer experience — really shine.

You can download the binaries here, or read on for some of the feature highlights.

Component Discovery

Otherwise known as convention-driven registration or scanning, Autofac 2 can register a set of types from an assembly according to user-specified rules:

var dataAccess = Assembly.GetExecutingAssembly();

builder.RegisterAssemblyTypes(dataAccess)
    .Where(t => t.Name.EndsWith("Repository"))
    .AsImplementedInterfaces();

The registration syntax for RegisterAssemblyTypes() is a superset of the registration syntax for single types, so methods like As<T>() all work with assemblies as well, and there’s very little extra API to learn.

Relationship Types

When working with IoC you frequently hear advice against passing the container around or resolving components from it directly. Where dynamic relationships are concerned, for example deferred creation, selection from alternatives or parameterisation, there has historically been very little guidance on the alternatives.

Autofac addresses this by automatically supporting small, focused, strongly-typed wrappers that express dynamic dependencies.

For example, instead of calling IContainer.Resolve<IDownloader>(), a WebCrawler component that needs to create instances of a downloader on-the-fly can take a dependency on Func<IDownloader> and the container will provide it automatically so long as IDownloader is registered.

class WebCrawler : IWebCrawler
{
    Func<Uri, IDownloader> _downloaderFactory;
   
    public WebCrawler (Func<Uri, IDownloader> downloaderFactory)
    {
        _downloaderFactory = downloaderFactory;
    }

    public void Crawl()
    {
        var downloader = _downloaderFactory(new Uri("http://autofac.org"));
        foreach (var link in downloader.OutboundLinks)
            // ...
    }
}

As the example shows, you can pass parameters (in this case a Uri) that will be forwarded to the target component’s constructor.

Autofac 2 supports an extensive vocabulary of relationship types that the container understands and provides automatically based on the other available components.

Relationship Adapter Type Meaning
A needs a B None Dependency
A needs a B at some point in the future Lazy<B> Delayed instantiation
A needs a B until some point in the future Owned<B> Controlled lifetime
A needs to create instances of B Func<B> Dynamic instantiation
A provides parameters of types X and Y to B Func<X,Y,B> Parameterisation
A needs all the kinds of B IEnumerable<B> Enumeration
A needs to know X about B before using it Meta<T> and Meta<B,X> Metadata interrogation

For more information on relationship types, see the introductory article.

Component Metadata

If you’re familiar with the Managed Extensibility Framework (MEF) you have probably seen examples using component metadata.

Autofac uses the underlying support in .NET 4.0 to provide similar functionality. Metadata is associated with a component either in code:

builder.Register(c => new ScreenAppender())
    .As<ILogAppender>()
    .WithMetadata("AppenderName", "screen");

Or in XML:

<component
   type="MyApp.Components.Logging.ScreenAppender, MyApp"
   service="MyApp.Services.Logging.ILogAppender, MyApp" >
    <metadata>
        <item name="AppenderName" value="screen" type="System.String" />
    </metadata>
</component>

Unlike a regular property, a metadata item can be queried and used without requiring an instance of the component to be created.

This makes it useful when selecting one of many components based on runtime criteria; or, where the metadata isn’t intrinsic to the component implementation. Metadata could represent the time that an ITask should run, or the button caption for an ICommand.

Other components can consume metadata using the System.Lazy<T,TMetadata> type.

public class Log
{
    readonly IEnumerable<Lazy<ILogAppender, ILogAppenderMetadata>> _appenders;

    public Log(IEnumerable<Lazy<ILogAppender, ILogAppenderMetadata>> appenders)
    {
        _appenders = appenders;
    }

    public void Write(string destination, string message)
    {
        var appender = _appenders.First(a => a.Metadata.AppenderName == destination);
        appender.Value.Write(message);
    }
}

In .NET 3.5 (as well as 4.0) Autofac 2 provides the weakly typed Meta<T> class for consuming metadata as a dictionary.

Managed Extensibilty Framework Integration

MEF introduces a standard API for creating extensible applications in .NET 4.0. If your Autofac-based application has extensibility points, plugin developers can use the MEF attributes to mark up their extensions, while internally they can be hosted in the Autofac container just like any other Autofac component.

Any MEF catalog type can be registered directly with the container, so to use MEF’s directory scanning ability for example, a System.ComponentModel.Composition.DirectoryCatalog can be used.

var catalog = new DirectoryCatalog("Extensions");

builder.RegisterComposablePartCatalog(catalog);

For documentation on this API see the Autofac MEF integration wiki page.

There’s a deeper discussion of the underlying architecture here.

Other Improvements

Although Autofac 2 introduces some new features, a lot more work went into making the core architecture and API of Autofac more consistent, robust and explicit.

To list a very small selection:

  • Generic type constraints are now respected – Autofac won’t try to use unsuitable generic types when resolving references to generic services.
  • The instance parameters to activation events are strongly-typed, for example builder.RegisterType<Foo>().OnActivating(e => e.Instance.Start()).
  • ASP.NET MVC controller registration is more flexible and simpler via the RegisterControllers() method.
  • Non-shared (‘factory’) scope is the default, rather than Singleton.
  • “Resolve Anything” support
  • API documentation is seachable on Google.

Upgrading from Autofac 1.4

If you’re upgrading from an earlier Autofac release, see the New in V2 wiki page for more detailed information.

There are many breaking changes for users of Autofac 1.4 who want to upgrade. Most of these are just name changes, but some less commonly-used features will cause non-trivial rework. This is the price of keeping Autofac clean, supportable and relevant – if you’re affected by breaking changes you can find consolation in knowing that Autofac is not on the path to becoming a legacy framework :) .

If things do get tough, help is only ever an email away.

Where to Next?

The 2.1 release is largely foundational — its focus is on improving the core container. There are plenty of new features in it, but next in the pipeline is a 2.2 version including, for example, broader ASP.NET MVC support and no doubt some fixes and improvements based on learnings from 2.1.

Acknowledgements and Thanks

Autofac 2 draws on many inspirations and input from a large community. Direct credit for Autofac 2 belongs to the project members, contributors to the mailing list, and supporters in the blogosphere, on stackoverflow and on Twitter.

Many of the ideas in Autofac 2, just as with the version before it, derive from other projects like Windsor, MEF, Funq, Unity, Ninject, StructureMap and their precursors.

Extra thanks is due to the MEF team, whose tireless work is making the .NET a friendlier place for IoC every day.

The Must-Have Tablet for 2010

Quartet Cube

Quartet Cube

If you’re a fan of index cards or Post-it notes for work item tracking, here’s another simple helper you might enjoy.

The Quartet Cube is a tiny, portable metallic whiteboard.

On our recent project we’ve kept three in the project room and found them perfect for:

  • Taking notes during meetings
  • Small focused to-do lists (we often use a pink one to track things we’d like to refactor)
  • Sketching ideas
  • Communicating designs (as demonstrated in the photo by the remarkable Steven Nagy)

The added portability makes it easy to take one to your desk – or to somebody else’s.