La terminologia della domanda non corrisponde esattamente al codice di esempio. Il Ambient Context
è un pattern utilizzato per afferrare una dipendenza da qualsiasi classe in qualsiasi modulo nel modo più semplice possibile, senza inquinare ogni classe per accettare l'interfaccia della dipendenza, mantenendo comunque l'idea di inversione del controllo. Tali dipendenze sono solitamente dedicate alla registrazione, alla sicurezza, alla gestione delle sessioni, alle transazioni, alla memorizzazione nella cache, alla verifica in modo da soddisfare ogni esigenza trasversale in quella applicazione. È in qualche modo fastidioso aggiungere un ILogging
, ISecurity
, ITimeProvider
ai costruttori e il più delle volte non tutte le classi hanno bisogno di tutte allo stesso tempo, quindi capisco le tue necessità.
Che cosa succede se la durata dell'istanza ISession
è diversa da ILogger
uno? Forse l'istanza di ISession dovrebbe essere creata una volta su ogni richiesta e su ILogger. 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 gestione e localizzazione a vita e altri descritti in questa discussione.
Il IAmbientContext
nella domanda non risolve il problema di non inquinare ogni costruttore. 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. Seleziona Thread.CurrentPrincipal che è una proprietà statica che restituisce un'implementazione dell'interfaccia IPrincipal
. È anche impostabile in modo da poter cambiare l'implementazione, se ti piace così, quindi non sei abbinato ad esso.
MyCore
sembra ora qualcosa di simile
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 che utilizzi.
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. L'Ambient Context dovrebbe essere l'ultima risorsa perché i suoi clienti nascondono le loro dipendenze attraverso di essa. Userei ancora Ambient Context se l'interfaccia in realtà imita 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 ottenere queste dipendenze onnipresenti.