37

I'm registering components with the following code:

StandardKernel kernel = new StandardKernel();

string currentDirectory = Path.GetDirectoryName(GetType().Assembly.Location)
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
    if (!Path.GetDirectoryName(assembly.Location).Equals(currentDirectory)) 
        continue;

    foreach (var type in assembly.GetTypes())
    {
        if (!type.IsComponent()) 
            continue;

        foreach (var @interface in type.GetInterfaces())
        kernel.Bind(@interface).To(type).InSingletonScope();
    }
}

Then I have a class which implements two interfaces:

class StandardConsole : IStartable, IConsumer<ConsoleCommand>

If I resolve IStartable I get one instance, if I resolve IConsumer<ConsoleCommand> I get another.

How do I get the same instance for both interfaces?

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • 1
    This question should be split into two, one for Ninject and the other for autofac. – Jeff Walker Code Ranger Feb 22 '12 at 00:20
  • @JeffWalkerCodeRanger: You gave -1 for that? :) – jgauffin Feb 22 '12 at 05:40
  • 1
    There are 3 or 4 dups on the Ninject side, see http://stackoverflow.com/questions/3147996/binding-singleton-to-multiple-services-in-ninject Removed ninject tag on that basis. Suggest removing ninject aspect from question as this makes for an unanswerable question – Ruben Bartelink Sep 12 '12 at 08:55

5 Answers5

79
builder.RegisterType<StandardConsole>()
   .As<IStartable>()
   .As<IConsumer<ConsoleCommand>>()
   .SingleInstance();

Very widely used feature of Autofac- any problems then there is a bug somewhere :)

Hth Nick

Edit By the looks of it, you're after the overload of As() that takes an IEnumerable<Type>() - check out all of the As() overloads using IntelliSense, something there should fit your scenario. As another commenter noted, you need to update the question with all of the info.

Nicholas Blumhardt
  • 30,271
  • 4
  • 90
  • 101
  • No, I do not want to register using IEnumerable. It's a built in feature in autofac. Also, i can't use generic parameters since I'm using reflection to register all components. – jgauffin Jul 08 '10 at 15:59
  • 2
    I know the feature you mean (I wrote it ;)) - the one I'm suggesting is different. If you have a list of the interfaces you want to expose (i1, i2, i3..) you can just pass the whole list to a single As() call. You might also check out RegisterAssemblyTypes(myAsm).AsImplementedInterfaces(), which can be extended to do what your article is proposing http://code.google.com/p/autofac/wiki/Scanning - you're welcome to work through this via the Autofac discussion forum if you like. – Nicholas Blumhardt Jul 08 '10 at 23:15
  • Sorry =) Just got tired of answer from people that hadn't used autofac. I've updated my answer below with code from the Scanning article. Thanks! – jgauffin Jul 09 '10 at 08:54
3

Updated with suggestion from Nicholas:

Here is how it's done in autofac

    private void BuildComponents(ContainerBuilder builder)
    {
        string currentDirectory = Path.GetDirectoryName(GetType().Assembly.Location);
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            if (!Path.GetDirectoryName(assembly.Location).Equals(currentDirectory))
                continue;

            builder.RegisterAssemblyTypes(assembly)
                .Where(t => t.IsComponent())
                .AsImplementedInterfaces()
                .SingleInstance();
        }
    }

    public static bool IsComponent(this Type value)
    {
        return value.GetType().GetCustomAttributes(typeof (ComponentAttribute), true).Length > 0;
    }
jgauffin
  • 99,844
  • 45
  • 235
  • 372
2

I know this is an old thread, but here is the solution for Ninject.

kernel.Bind<StandardConsole>().ToSelf().InSingletonScope();
kernel.Bind<IStartable>().ToMethod(ctx => ctx.Kernel.Get<StandardConsole>());
kernel.Bind<IConsumer<ConsoleCommand>>().ToMethod(ctx => ctx.Kernel.Get<StandardConsole>());
Nick Olsen
  • 6,299
  • 11
  • 53
  • 75
0

This is me taking a wild stab in the dark as I don't know Autofac.

If you add:

build.RegisterType<StandardConsole>.As(StandardConsole).SingleInstance()

then shouldn't it resolve IStartable to StandardConsole then StandardConsole to the singleton instance of StandardConsole? Ditto with IConsumer.

EDIT: From logging at your blog, couldn't you change the following:

assemblies.Each(assembly => assembly.FindComponents((i, c) => builder.RegisterType(c).As(i).SingleInstance()));

to

assemblies.Each(assembly => assembly.FindComponents((i, c) => {
    builder.RegisterType(c).As(i).SingleInstance();
    builder.RegisterType(c).As(c).SingleInstance();
}));
Wysawyg
  • 712
  • 8
  • 22
0

I'm not familiar with Autofac, but you ought to be able to Register for one type a lambda expression that returns the Resolve of the other type.

something like:

builder.Register<IStartable>().As<StandardConsole>().Singleton();
builder.Register<IConsumer<ConsoleCommand>>().As( x => builder.Resolve<IStartable>() );
Dave Thieben
  • 5,388
  • 2
  • 28
  • 38
  • 1
    No can do. I scan all assemblies in the application directory after classes with a ComponentAttribute and register them with all interfaces that they implement. That makes it quite hard to do what you suggest. http://blog.gauffin.org/2010/07/simplified-autofac-registrations/ – jgauffin Jul 07 '10 at 18:45