2011-12-05 2 views
6

ho un modulo Autofac che ha la seguente (assettato giù) della logica nella esclusione di carico:arresto Autofac modulo registrazione già registrati

protected override void Load(ContainerBuilder builder) 
    { 
     foreach (var componentType in allTypesInAllAvailableAssemblies) // Set elsewhere 
     { 
      var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>))); 
      if (handlerInterfaces.Any()) 
       builder.RegisterType(componentType).As(handlerInterfaces); 
     } 
    } 

Questo è alla ricerca di qualsiasi classe che si dichiara un gestore di messaggi e lo registra contro tutte le interfacce IMessageHandler che implementa.

Quello che voglio fare è non registrare il componente se è già registrato. Come bonus, sarebbe l'ideale se potessi aggiornare la registrazione esistente per risolverlo con le interfacce del gestore dei messaggi se non lo è già.

Per amor di discussione si può presumere che questo codice verrà eseguito dopo tutti gli altri tipi sono stati registrati (inclusi i possibili candidati gestore di messaggi)

Ho usato l'override AttachToComponentRegistration per la manipolazione iscrizione nel passato ma non sembra che sia utile in questo scenario.

È possibile o devo riconsiderare il design e forzare i plug-in per dichiarare esplicitamente i gestori?

+0

Hai provato a utilizzare la classe AnyConcreteTypeNotAlreadyRegisteredSource?Vedi: http://stackoverflow.com/questions/3413660/ –

risposta

7
builder.RegisterType(componentType) 
    .As(handlerInterfaces) 
    .PreserveExistingDefaults(); 

Funzionerà se non si avvia la risoluzione degli elenchi di gestori.

+0

Purtroppo ho bisogno di liste di gestori. Ho finito per modificare la registrazione inviata per cercare tutte le interfacce del gestore quando un tipo è registrato esplicitamente piuttosto che eseguire un'altra scansione di tutti i tipi. Saluti per l'aiuto - Ho accettato questo dato che risponde alla domanda come postata. – JRoughan

1

Sfortunatamente non esiste un modo elegante per fare quello che vuoi. Il contenitore Autofac e il suo builder sono "scatole nere" che non ti permettono di dare una buona occhiata a ciò che hai già.

Non c'è nulla di male nella registrazione di un componente due volte, A MENO CHE le registrazioni siano in ordine di ordine (BAD, BAD, BAD). Registrarsi una seconda volta semplicemente sovrascriverà la vecchia registrazione con la nuova.

Ho seriamente messo in discussione questo codice, in quanto dipende totalmente da come viene inizializzato allTypesInAllAvailableAssemblies. Se è veramente di ogni tipo nel tuo sistema, allora è un tiro di merda su cosa si risolverà, per esempio, su un IDisposable. Se disponi di diverse implementazioni diverse, ad esempio IConfigurator, avrai un controllo limitato su chi termina la registrazione, indipendentemente dal fatto che tu stia verificando ciò che è già registrato o semplicemente lasciando che la registrazione venga sovrascritta; dipende totalmente da quale classe finisce per prima (o ultima) nella lista.

L'unica cosa che riuscivo a pensare a fare è usare un po 'di Linq per assicurarsi che l'elenco dei tipi che si sta registrando è unico nel suo genere:

protected override void Load(ContainerBuilder builder) 
{ 
    foreach (var componentType in allTypesInAllAvailableAssemblies.OfType<Type>().Distinct()) // Set elsewhere 
    { 
     var handlerInterfaces = componentType.GetInterfaces().Where(i => i.IsClosedTypeOf(typeof(IMessageHandler<>))); 
     if (handlerInterfaces.Any()) 
      builder.RegisterType(componentType).As(handlerInterfaces); 
    } 
} 

Questo garantirà che ogni istanza di componentType è mai stato visto prima dal costruttore, nell'ambito di questo ciclo foreach. Ciò significa che, dato che questo è l'unico modulo utilizzato per compilare i Container, e ogni Container è costruito una sola volta e non è mai aggiornato, ogni componente del sistema sarà stato registrato in un determinato Container esattamente una volta. Interfacce comuni, come IDisposable, IEnumerable, IComparable, IComparer, ecc. Saranno inutili da provare a risolvere; si risolveranno in un'istanza dell'ultima classe con quell'interfaccia.

Se è necessario verificare che un'interfaccia non sia mai stata registrata, o che questo codice funzioni anche quando si utilizza ContainerBuilder per aggiornare() un contenitore esistente, basta interrompere ciò che si sta facendo perché si sta per creare un senza speranza pasticcio che non sarai mai in grado di mantenere correttamente.

+0

Ciò è dovuto al fatto che ho un doppio meccanismo di registrazione inviato per i plug-in (ad esempio viene fornita una classe che espone i metodi di registrazione e li aggiunge internamente al builder). Questo è bello e pulito e può essere usato per registrare i gestori ma stavo cercando un modo per non forzare i plugin a registrare esplicitamente tutti i loro gestori individualmente (usando questo modulo nella shell). Anche questo funziona bene, tranne quando un componente è registrato nella spedizione ma è anche un gestore di messaggi (specialmente se le durate variano). – JRoughan

+0

Nessun problema con più interfacce esistenti nel sistema (in realtà è previsto). Non è inoltre previsto l'aggiornamento dei contenitori esistenti o la dipendenza degli ordini dalle registrazioni. Probabilmente non ho spiegato lo scenario come avrei potuto, ma non è così male come probabilmente stai pensando. – JRoughan

+0

Oh e allTypesInAllAvailableAssemblies esiste solo nell'esempio SO. Nel mondo reale i tipi disponibili sono forniti da un'altra classe con alcune intelligenze al suo interno. – JRoughan