La terminologia della domanda non corrisponde realmente al codice di esempio. Questo Ambient Context
è un modello usato per afferrare una dipendenza da qualsiasi classe in qualsiasi modulo il più semplice possibile, senza inquinare ogni classe per accettare l'interfaccia della dipendenza, ma mantenendo comunque l'idea di inversione del controllo. Tali dipendenze sono di solito dedicate alla registrazione, alla sicurezza, alla gestione delle sessioni, alle transazioni, alla memorizzazione nella cache, all'audit, quindi a qualsiasi preoccupazione trasversale in tale applicazione. E 'in qualche modo fastidioso per aggiungere un ILogging
, ISecurity
, ITimeProvider
ai costruttori e il più delle volte non tutte le classi bisogno di tutto, allo stesso tempo, quindi capisco la vostra esigenza.
Cosa succede se la durata ISession
dell'istanza è diversa da ILogger
quella? Forse l'istanza ISession dovrebbe essere creata su ogni richiesta e su ILogger una volta. Quindi avere tutte queste dipendenze governate da un oggetto che non è il contenitore stesso non sembra la scelta giusta a causa di tutti questi problemi con la gestione e la localizzazione a vita e altri descritti in questo thread.
La IAmbientContext
domanda non risolve il problema di non inquinare tutti i costruttori. Devi ancora usarlo nella firma del costruttore, certo, una volta solo questa volta.
Quindi il modo più semplice NON è usare l'iniezione del costruttore o qualsiasi altro meccanismo di iniezione per gestire le dipendenze trasversali, ma usando una chiamata statica . In realtà vediamo questo schema abbastanza spesso, implementato dal framework stesso. Controllare Thread.CurrentPrincipal che è una proprietà statica che restituisce un'implementazione IPrincipal
dell'interfaccia. È anche configurabile in modo da poter modificare l'implementazione se lo desideri, quindi non sei accoppiato ad esso.
MyCore
sembra ora qualcosa del genere
public class MyCoreClass
{
public void BusinessFeature(string data)
{
LoggerContext.Current.Log(data);
_repository.SaveProcessedData();
SessionContext.Current.SetData(data);
...etc
}
}
Questo modello e le possibili implementazioni sono state descritte in dettaglio da Mark Seemann in questo articolo . Potrebbero esserci implementazioni che si basano sul contenitore IoC stesso che usi.
Vuoi evitare AmbientContext.Current.Logger
, AmbientContext.Current.Session
per gli stessi motivi descritti sopra.
Ma hai altre opzioni per risolvere questo problema: usa decoratori, intercettazione dinamica se il tuo contenitore ha questa capacità o AOP. Il contesto ambientale dovrebbe essere l'ultima risorsa a causa del fatto che i suoi clienti nascondono le loro dipendenze attraverso di esso. Userei ancora Ambient Context se l'interfaccia imita davvero il mio impulso di usare una dipendenza statica come DateTime.Now
o ConfigurationManager.AppSettings
e questa necessità aumenta abbastanza spesso. Ma alla fine l'iniezione del costruttore potrebbe non essere una cattiva idea per ottenere queste dipendenze onnipresenti.
IService
utilizzato per comunicare con un altro servizio?" SeIService
rappresenta una vaga dipendenza da altri servizi, allora sembra un localizzatore di servizi e non dovrebbe esistere. La tua classe dovrebbe dipendere da interfacce che descrivono esplicitamente cosa farà il loro consumatore con loro. Nessuna classe ha mai bisogno di un servizio per fornire l'accesso a un servizio. Una classe ha bisogno di una dipendenza che fa qualcosa di specifico di cui la classe ha bisogno.