Autofac in web applications, where should I store the container for easy access?
Asked Answered
C

5

15

I'm still pretty new to using Autofac and one thing I miss in the documentation and examples is how to make it easy to get to the configured container from different places in a web application.

I know I can use the Autofac controller factory to automatically resolve constructor injected dependencies for controllers, but how about the other stuff you might need to resolve that is not injected yet.

Is there an obvious pattern I am not aware of for this?

Thank you!

Conspiracy answered 13/3, 2009 at 21:50 Comment(1)
BTW this question was asked when MVC was at version 2. In MVC 3, DependencyResolver.Current is all you need whether you're using Autofac or something else.Blunge
A
13

First of all try not to overuse the IoC container. Its great for "wiring up" controllers, views and services but objects that need to be created during runtime should be created by factory objects and not by the container. Otherwise you get Container.Resolve calls all through your code, tying it to your container. These extra dependencies defeat the purpose of using IoC. In most cases I can get by only resolving one or two dependencies at the top level of my application. The IoC container will then recursively resolve most dependencies.

When I need the container elsewhere in my program here's a trick I often use.

public class Container : IContainer
{
    readonly IWindsorContainer container;

    public Container()
    {
        // Initialize container
        container = new WindsorContainer(new XmlInterpreter(new FileResource("castle.xml")));

        // Register yourself
        container.Kernel.AddComponentInstance<IContainer>(this);
    }

    public T Resolve<T>()
    {
        return container.Resolve<T>();
    }
}

I wrap the container in a Container class like this. It adds itself to the wrapped container in the constructor. Now classes that need the container can have an IContainer injected. (the example is for Castle Windsor but it can probably be adapted for AutoFac)

Anemia answered 13/3, 2009 at 21:59 Comment(0)
B
32

The Autofac "way" is to have an IContext constructor parameter. Autofac will inject an object that can be used to resolve types.

The context is usually the container behind the scenes, IContainer implements the IContext interface, though IContext is limited to only doing resolves.

I know that the container should not be "overused", but I have, as the OP, classes that requires resolving types that is not known ahead of time (and thus cannot be used as constructor params). I find it useful in these cases, to think of the container as yet another service that can be used to resolve other services, and inject that like any other service.

If you feel that using IContext binds you to Autofac and you need to abstract that with your own interface this is just a matter of registering an IContext wrapper class with your container.

Update: in Autofac 2, the IContext is called IComponentContext.

Burrus answered 20/7, 2009 at 16:16 Comment(4)
Why not inject a factory instead?Sago
@Sago - ...and the difference being?Burrus
Again, the clue here is that not always (and especially with legacy code not built with DI in mind) is the types of required services not known at compile time. Thus a "non-strongly" typed factory is required. The IContext is just that, a factory that can produce instances of the types one tries to resolve.Burrus
Seems to be an autofac 1.0 feature, now missing from v2Ashil
A
13

First of all try not to overuse the IoC container. Its great for "wiring up" controllers, views and services but objects that need to be created during runtime should be created by factory objects and not by the container. Otherwise you get Container.Resolve calls all through your code, tying it to your container. These extra dependencies defeat the purpose of using IoC. In most cases I can get by only resolving one or two dependencies at the top level of my application. The IoC container will then recursively resolve most dependencies.

When I need the container elsewhere in my program here's a trick I often use.

public class Container : IContainer
{
    readonly IWindsorContainer container;

    public Container()
    {
        // Initialize container
        container = new WindsorContainer(new XmlInterpreter(new FileResource("castle.xml")));

        // Register yourself
        container.Kernel.AddComponentInstance<IContainer>(this);
    }

    public T Resolve<T>()
    {
        return container.Resolve<T>();
    }
}

I wrap the container in a Container class like this. It adds itself to the wrapped container in the constructor. Now classes that need the container can have an IContainer injected. (the example is for Castle Windsor but it can probably be adapted for AutoFac)

Anemia answered 13/3, 2009 at 21:59 Comment(0)
C
9

Having IOC container globally available is not a best practice. Even passing container is not encouraged.

If dependency injection can not be used (you need to create\request objects after component has been created) then you can:

  1. Use hand-coded factories (factory is injected to the component and component uses factory to create other objects)
  2. Use Autofac delegate factories or new auto-generated factories in Autofac 2.
Clapperclaw answered 10/11, 2009 at 6:51 Comment(1)
huzzah for not using the container as a service locatorHathaway
B
6

Peter Lillevold's response above is correct - you can access the container from any component by taking a dependency on the IContext interface.

If you really do need the actual container reference, see Autofac.Integration.Web.IContainerProviderAccessor.

Blunge answered 1/8, 2009 at 20:18 Comment(0)
G
1

The usual way of doing this is to store the container in a static variable in your Global app class.

Grimm answered 13/3, 2009 at 21:52 Comment(1)
Ah, but be careful which container you store! You don't wnat the application-container, that's for sure!Stokowski

© 2022 - 2024 — McMap. All rights reserved.