2012-07-04 9 views
6

mi sembra di fare questo un bel po 'nel mio codice:È necessario associare in modo esplicito le normali classi utilizzando Autofac?

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(); 
     } 
    } 
} 

Dove classe delle 'azioni' è una classe ho bisogno per essere iniettato in mio controller, e ha vari altri sub-dipendenze.

Sembra un po 'spazzatura. Perché non è possibile che autofac risolva il fatto che la classe abbia un costruttore con dipendenze che sono già soddisfatte e che producono automaticamente un'istanza?

Voglio dire, se la classe A richiede che la classe B venga iniettata e la classe B richieda C, D, E, ecc. Abbastanza giusto, immagino che tu non voglia percorrere l'intera catena di dipendenze per vedere se puoi fare una classe in fase di esecuzione. ... ma se la classe A dipende direttamente da C e D che sono esplicitamente vincolati, sicuramente questo è un caso banale?

Mi manca qualcosa? Non riesco a vedere alcuna documentazione per questo ...

risposta

2

AFAIK, Autofac richiede che tutti i tipi necessari siano registrati nel contenitore, ma questo non significa che devi eseguire ognuno individualmente. Quasi il 99% delle mie registrazioni sono gestite con l'aggiunta di questo attributo del tipo:

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

Così, per esempio, si avrebbe

[AutoRegister] 
class ComboActions 
{ 

E poi li ho registrati con questo:

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(); 
    } 
} 

Come ho detto, questo copre la maggior parte delle mie registrazioni e quindi di solito devo solo preoccuparmi di cose come i tipi di terze parti, i generici e i decoratori aperti.

MODIFICA: Controlla lo reply from Kaleb che mi dà ragione. Caratteristica interessante che non ho mai saputo!

20

Non è necessario registrare ogni tipo. Autofac fornisce uno AnyConcreteTypeNotAlreadyRegisteredSource che acquisirà automaticamente un tipo concreto se non hai già fornito una registrazione.

Ad esempio:

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

Le fonti permettono le cose più complesse, come automatically injecting mocked objects per le interfacce e le dipendenze astratti a base di classe.

+0

Whoah. Mai saputo di questo. TIL! –

+1

questo è INCREDIBILE, specialmente perché si può fare qualcosa come 'builder.RegisterSource (new AnyConcreteTypeNotAlreadyRegisteredSource (x => x.Name.Contains (" ViewModel ")));' –

Problemi correlati