Thursday, September 22, 2011

Resolve Autofac IContainer Dependency Injection

    Today, i come to a need of using Autofac IContainer somewhere in my code. I know it's a bad practice using IContainer this way but i'm pretty sure sometime we must violate the convention. I'll show you the reason and the case on next post. Now i just say about how to have the IContainer itself resolvable in some of the classes. I guess perhaps that's the intention of the Autofac author not to make the IContainer interface to be the dependency of classes. However, we have the ServiceLocator anyway so it's not that easy to force the developer following best practices.
    Okey, here is the problem. We have the ContainerBuilder to register types, instances, etc and in the end we build the container builder to return the container instance. So If I register the instance of IContainer using the way below, it's not gonna work:

var builder = new ContainerBuilder();
// Register other dependencies in your app

IContainer container = null;
builder.RegisterInstance(container);

container = builder.Build();

The reason is we cannot register a null object. So here is the work around:
var builder = new ContainerBuilder();
// Register other dependencies in your app

IContainer container = null;
Func<IContainer> factory = () => container;
builder.RegisterInstance(factory);

container = builder.Build();

And in our code, we will make the factory to be it's dependency:
public class MyClass
{
    public MyClass(Func<IContainer> containerFactory)
    {
    }
}

Dirty, but works :D

3 comments:

Van Nguyen said...

Just need IComponentContext or ILifetimeScope for most purposes. These are automatically provided by Autofac, so all you need to do is take a (constructor) dependency on one of them and the current instance will be injected.

Markus said...

You can avoid using a function if you register the IContainer interface with an updater:

// Add the container to it's own registry
var updater = new ContainerBuilder();
updater.RegisterInstance(container).Named("root");
updater.Update(container);

Van Nguyen said...

Thank mate, I used IComponentContext instead, work like a charm.

Post a Comment