La terminologie de la question ne correspond pas vraiment à l'exemple de code. Le Ambient Context
est un modèle utilisé pour récupérer une dépendance de n'importe quelle classe dans n'importe quel module aussi facilement que possible, sans polluer chaque classe pour accepter l'interface de la dépendance, mais en gardant toujours l'idée d'inversion de contrôle. De telles dépendances sont généralement dédiées à la journalisation, à la sécurité, à la gestion de session, aux transactions, à la mise en cache, à l'audit, ainsi à tout problème transversal dans cette application. Il est en quelque sorte gênant d'ajouter un ILogging
, ISecurity
, ITimeProvider
aux constructeurs et la plupart du temps toutes les classes ont besoin tout en même temps, donc je comprends votre besoin.
Et si la durée de vie de l' ISession
instance est différente de ILogger
celle? Peut-être que l'instance ISession devrait être créée à chaque demande et l'ILogger une fois. Donc, avoir toutes ces dépendances régies par un objet qui n'est pas le conteneur lui-même ne semble pas le bon choix en raison de tous ces problèmes avec la gestion et la localisation de la durée de vie et d'autres décrits dans ce fil.
La IAmbientContext
question ne résout pas le problème de ne pas polluer tous les constructeurs. Vous devez toujours l'utiliser dans la signature du constructeur, bien sûr, une seule fois cette fois.
Donc, le moyen le plus simple n'est PAS d'utiliser l'injection de constructeur ou tout autre mécanisme d'injection pour gérer les dépendances transversales, mais en utilisant un appel statique . Nous voyons en fait ce modèle assez souvent, mis en œuvre par le cadre lui-même. Vérifiez Thread.CurrentPrincipal qui est une propriété statique qui renvoie une implémentation de l' IPrincipal
interface. Il est également paramétrable pour que vous puissiez modifier l'implémentation si vous le souhaitez, donc vous n'y êtes pas associé.
MyCore
ressemble maintenant à quelque chose comme
public class MyCoreClass
{
public void BusinessFeature(string data)
{
LoggerContext.Current.Log(data);
_repository.SaveProcessedData();
SessionContext.Current.SetData(data);
...etc
}
}
Ce modèle et les implémentations possibles ont été décrits en détail par Mark Seemann dans cet article . Il peut y avoir des implémentations qui dépendent du conteneur IoC lui-même que vous utilisez.
Vous souhaitez éviter AmbientContext.Current.Logger
, AmbientContext.Current.Session
pour les mêmes raisons que celles décrites ci-dessus.
Mais vous avez d'autres options pour résoudre ce problème: utilisez des décorateurs, l'interception dynamique si votre conteneur a cette capacité ou AOP. Le contexte ambiant devrait être le dernier recours car ses clients cachent leurs dépendances à travers lui. J'utiliserais toujours le contexte ambiant si l'interface imite vraiment mon impulsion à utiliser une dépendance statique comme DateTime.Now
ou ConfigurationManager.AppSettings
et ce besoin augmente assez souvent. Mais à la fin, l'injection de constructeur pourrait ne pas être une si mauvaise idée pour obtenir ces dépendances omniprésentes.
IService
utilisé pour communiquer avec un autre service?" SiIService
représente une vague dépendance vis-à-vis d'autres services, cela ressemble à un localisateur de services et ne devrait pas exister. Votre classe doit dépendre d'interfaces qui décrivent explicitement ce que leur consommateur en fera. Aucune classe n'a jamais besoin d'un service pour donner accès à un service. Une classe a besoin d'une dépendance qui fait quelque chose de spécifique dont la classe a besoin.