views:

1119

answers:

3

I've read about Autofac that it's fast. I've seen the coding involved and it's preatty neat. But I'm not quite sure how to use it. I've used StructureMap, and it has a static ObjectFactory. Ninject has the Kernel, but in autofac's google pages they recomend doing something like this :

using( var resolver = builder.Build() ){
   var whatINeed = resolver.Resolve<INeedThisService>();
}

It's a WinForms app, so I got a Invalid Object state from doing the above, so I swiched to having a global IContainer, and did it this way

 using( var resolver = Program.Container.CreateInnerContainer() )
 {
     var whatINeed = resolver.Resolve<INeedThisService>();
 }

I've used it about 3 or 5 times. But is that eficient ? Or should I just do something like

 var whatINeed = Program.Resolve<INeedThisService>()

and under the covers

 internal static TServervice Resolver<TService>(){
       if(_container == null ) _container = builder.Build();
       return _container.Resolve<TService>();
 }

Wich would you use, and why. Also is there a penalty for working with CreateInnerContainer()?

+5  A: 

I am not an AutoFac expert but do have experience with other Ioc containers. I thought this question would give me a reason to try AutoFac.

Designs based on Ioc containers should strive to isolate all code from having access to the container except at the entry point or host level. I created the following example using AutoFac and WinForms to show how a form could access a service via it's constructor.

I'm not quite sure why you thought you needed the inner container. Perhaps you could comment and I can provide a more detailed response.

static class Program
{
    [STAThread]
    static void Main()
    {
        var builder = new ContainerBuilder();
        builder.Register<TheService>().As<INeedThisService>();
        builder.Register(f => new Form1(f.Resolve<INeedThisService>())).As<Form1>();

        using (var container = builder.Build())
        {
            Application.Run(container.Resolve<Form1>());
        }

    }
}

public interface INeedThisService { }

public class TheService : INeedThisService
{
    public TheService() { Console.WriteLine("ctor ThisService"); }
}

public partial class Form1 : Form
{
    public Form1(INeedThisService service)
    {
        Console.WriteLine("ctor Form1");
        InitializeComponent();
    }
}
Mark Lindell
I know how to use an IoC, I wanted something that was in the guidelines of the framework for having access to my services. With StructureMap is a clear solution, you just use ObjectFactory. But with Autofac is not that clear, and I would hate to have to re-register all the components
Mihai Lazar
Could you explain what you mean by "re-register" all the components. Are you looking for auto registration of all types in an assembly? I will go look at StructureMap's ObjectFactory in the meantime.
Mark Lindell
Re-register means to run the portion that generates an IContainer again. The question was how to get keep the IContainer if you run it through an using(..) statement.
Mihai Lazar
+2  A: 

As Mark Lindell pointed out, you don't generally need to access the container directly in an Autofac application.

The recommended approach is to access it once, as Mark has done, when the application starts up.

Other components that subsequently need to create objects can declare a constructor parameter of type IContext, which Autofac will automatically inject.

An alternative, that does not require any dependency on the Autofac assembly, is to use Generated Factories as described at: http://code.google.com/p/autofac/wiki/DelegateFactories

Hope this helps!

Nicholas Blumhardt
sorry, still not clear on the general guideline.The GeneratedFactories is an interesting approach though.
Mihai Lazar
+1  A: 

1) From the examples you gave I could make an assumption that you are trying to use IOC container primarily as service locator. Although almost all containers support it, main usage would be Dependency Injection. That means you should avoid calling Resolve method at all and let container inject all dependencies for you. The differences between two of them (Service Locator and Dependency Injection) is beyond this topic.

2) If you still want to use it as service locator you can just use root container (Program.Container in your case) without creating inner containers. The sequence would be:

  • Create ContainerBuilder
  • Register you components in the builder
  • Create root container: builder.Build()
  • Access root container to resolve component instances

3) Container hierarchies can be useful in the scenarios where you need singleton behaviour in different scopes:

  • Global \ Session \ Request (Web applications)
  • Application \ Plugin (Desktop plugin-based applications)

BTW Autofac encourage people to use tagged contexts to solve such problems:

Yes you are right, I was trying to use it as a service locator and DI. I was confused at the time, mostly because of how I was using StructureMap.
Mihai Lazar