Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Must I explicitly bind normal classes using Autofac?

Tags:

c#

autofac

I seem to be doing this a fair bit in my code:

public class ActionsModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            base.Load(builder);
            builder.Register(c => LogManager.GetCurrentClassLogger()).As<ILog>().InstancePerDependency();

            // Autofac doesn't seem to be able to inject things without explicit binding 
            builder.RegisterType<ComboActions>().As<ComboActions>().InstancePerHttpRequest();
            builder.RegisterType<AppActions>().As<AppActions>().InstancePerHttpRequest();
        }
    }
}

Where the 'actions' class is a class I require to be injected into my controller, and has various other sub-dependencies.

Seems a bit rubbish. Why can't autofac resolve that the class has a constructor with dependencies that are already satisfied and manufacture an instance automatically?

I mean, if class A requires class B to be injected and class B requires C, D, E, etc. fair enough, I guess you dont want to walk the entire dependency chain to see if you can make a class at run time. ...but if class A directly depends on C and D which are explicitly bound, surely that's a trivial case?

Am I missing something? Can't seem to see any documentation for this...

like image 916
Doug Avatar asked Jul 04 '12 04:07

Doug


2 Answers

You don't have to register every type. Autofac provides a AnyConcreteTypeNotAlreadyRegisteredSource that will automatically grab a concrete type if you haven't already provided a registration.

For example:

var builder = new ContainerBuilder();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var container = builder.Build();
...
var myConcreteType = container.Resolve<MyConcreteType>();

The sources allow more complex things, like automatically injecting mocked objects for interfaces and abstract class based dependencies.

like image 190
Kaleb Pederson Avatar answered Nov 13 '22 10:11

Kaleb Pederson


AFAIK, Autofac requires every needed type to be registered in the container, but this does not mean you have to do each one individually. Almost 99% of my registrations are handled by adding this attribute to the type:

[AttributeUsage(AttributeTargets.Class)]
public class AutoRegisterAttribute : Attribute { }

So for example, you'd have

[AutoRegister]
class ComboActions
{

And then I register them with this:

public class AutoScanModule : Module
{
    private readonly Assembly[] _assembliesToScan;

    public AutoScanModule(params Assembly[] assembliesToScan)
    {
        _assembliesToScan = assembliesToScan;
    }

    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterAssemblyTypes(_assembliesToScan)
            .Where(t => t.GetCustomAttributes(typeof (AutoRegisterAttribute), false).Any())
            .AsSelf()
            .AsImplementedInterfaces()
            .InstancePerLifetimeScope();
    }
}

Like I said, this covers most of my registrations and then I usually only have to worry about things like 3rd party types, open generics and decorators.

EDIT: Check out the reply from Kaleb that proves me wrong. Cool feature I never knew about!

like image 41
Jim Bolla Avatar answered Nov 13 '22 08:11

Jim Bolla