Die Terminologie aus der Frage stimmt nicht wirklich mit dem Beispielcode überein. Dies Ambient Context
ist ein Muster, das verwendet wird, um eine Abhängigkeit von einer Klasse in einem Modul so einfach wie möglich zu erfassen, ohne jede Klasse zu verschmutzen, um die Schnittstelle der Abhängigkeit zu akzeptieren, aber dennoch die Idee der Umkehrung der Kontrolle beizubehalten. Solche Abhängigkeiten sind normalerweise für Protokollierung, Sicherheit, Sitzungsverwaltung, Transaktionen, Caching und Prüfung vorgesehen, um Querschnittsthemen in dieser Anwendung zu berücksichtigen. Es ist irgendwie ärgerlich , Konstruktoren ein ,, hinzuzufügen ILogging
, und meistens brauchen nicht alle Klassen alle gleichzeitig, also verstehe ich Ihre Bedürfnisse.ISecurity
ITimeProvider
Was ist, wenn sich die Lebensdauer der ISession
Instanz von der unterscheidet ILogger
? Möglicherweise sollte die ISession-Instanz bei jeder Anforderung und der ILogger einmal erstellt werden. Wenn all diese Abhängigkeiten von einem Objekt gesteuert werden, das nicht der Container selbst ist, ist dies aufgrund all dieser Probleme mit der Lebensdauerverwaltung und -lokalisierung und anderen in diesem Thread beschriebenen Problemen nicht die richtige Wahl.
Das IAmbientContext
in der Frage löst nicht das Problem, nicht jeden Konstruktor zu verschmutzen. Sie müssen es natürlich immer noch nur einmal in der Konstruktorsignatur verwenden.
Der einfachste Weg ist also, KEINE Konstruktorinjektion oder einen anderen Injektionsmechanismus zu verwenden, um Querschnittsabhängigkeiten zu behandeln, sondern einen statischen Aufruf zu verwenden . Wir sehen dieses Muster tatsächlich ziemlich oft, implementiert durch das Framework selbst. Überprüfen Sie Thread.CurrentPrincipal , eine statische Eigenschaft, die eine Implementierung der IPrincipal
Schnittstelle zurückgibt . Es ist auch einstellbar, sodass Sie die Implementierung ändern können, wenn Sie dies möchten, sodass Sie nicht daran gebunden sind.
MyCore
sieht jetzt so aus wie
public class MyCoreClass
{
public void BusinessFeature(string data)
{
LoggerContext.Current.Log(data);
_repository.SaveProcessedData();
SessionContext.Current.SetData(data);
...etc
}
}
Dieses Muster und mögliche Implementierungen wurden von Mark Seemann in diesem Artikel ausführlich beschrieben . Möglicherweise gibt es Implementierungen, die auf dem von Ihnen verwendeten IoC-Container selbst basieren.
Sie wollen vermeiden AmbientContext.Current.Logger
, AmbientContext.Current.Session
aus den gleichen Gründen wie oben beschrieben.
Sie haben jedoch andere Möglichkeiten, um dieses Problem zu lösen: Verwenden Sie Dekoratoren, dynamisches Abfangen, wenn Ihr Container über diese Funktion verfügt, oder AOP. Der Umgebungskontext sollte der letzte Ausweg sein, da seine Clients ihre Abhängigkeiten dadurch verbergen. Ich würde immer noch Ambient Context verwenden, wenn die Schnittstelle wirklich meinen Impuls nachahmt, eine statische Abhängigkeit wie DateTime.Now
oder zu verwenden, ConfigurationManager.AppSettings
und dieser Bedarf steigt ziemlich oft. Aber am Ende ist die Konstruktorinjektion möglicherweise keine so schlechte Idee, um diese allgegenwärtigen Abhängigkeiten zu erhalten.
IService
für die Kommunikation mit anderen Diensten verwendet"? Wenn es sichIService
um eine vage Abhängigkeit von anderen Diensten handelt, klingt dies wie ein Dienstfinder und sollte nicht existieren. Ihre Klasse sollte von Schnittstellen abhängen, die explizit beschreiben, was ihre Verbraucher mit ihnen tun werden. Keine Klasse benötigt jemals einen Dienst, um Zugriff auf einen Dienst zu erhalten. Eine Klasse benötigt eine Abhängigkeit, die etwas Bestimmtes tut, das die Klasse benötigt.