Puis-je passer des paramètres du constructeur à la méthode Resolve () de l'unité?
-
16-09-2019 - |
Question
J'utilise l'unité de Microsoft pour l'injection de dépendance et je veux faire quelque chose comme ceci:
IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context
IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);
RepositoryA
et RepositoryB
les deux ont un constructeur qui prend un paramètre IDataContext
, et je veux l'unité pour initialiser le référentiel avec le contexte que je transmets. A noter également que IDataContext
n'est pas enregistré avec l'unité (je ne veux pas 3 cas de IDataContext
).
La solution
A ce jour, ils ont ajouté cette fonctionnalité:
Il est dans la dernière goutte ici:
http://unity.codeplex.com/SourceControl/changeset/view/33899
Discussion sur le sujet ici:
http://unity.codeplex.com/Thread/View.aspx? ThreadId = 66434
Exemple:
container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
Autres conseils
<2 cents>
Que faire si vous plus tard décidez d'utiliser un autre service qui nécessite plus ou moins que le contexte?
Le problème avec les paramètres du constructeur et la COI est que les paramètres sont finalement liés au type de béton utilisé, au lieu d'être une partie du contrat que l'interface de service définit.
Ma suggestion serait que vous soit résoudre le contexte aussi bien, et je crois que l'unité devrait avoir un moyen pour vous d'éviter la construction de 3 cas de celui-ci, ou vous devriez envisager un service d'usine qui a une façon pour vous de construire la objet.
Par exemple, si vous décidez par la suite de construire un référentiel qui ne repose pas sur une base de données traditionnelle du tout, mais au lieu d'utiliser un fichier XML pour produire des données fictives pour le test? Comment feriez-vous de nourrir le contenu XML à ce constructeur?
IoC est basé sur le code de découplage, en liant dans le type et la sémantique des arguments aux types concrets, vous avez vraiment pas fait correctement le découplage, il y a encore une dépendance.
« Ce code peut parler à tout type de dépôt peut-être, aussi longtemps qu'il implémente cette interface .... Oh, et utilise un contexte de données ».
Maintenant, je sais que d'autres conteneurs IoC supportent cela, et je l'avais dans ma première version de mon propre bien, mais à mon avis, il ne fait pas partie de l'étape de résolution.
2 cents>
Merci les gars ... Le mien est similaire au poste par « Exister ». Voir ci-dessous:
IUnityContainer container = new UnityContainer();
container.LoadConfiguration();
_activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
{
new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
});
Vous pouvez utiliser InjectionConstructor / InjectionProperty / InjectionMethod selon votre architecture d'injection dans le ResolvedParameter
Dans votre cas, cet objet doit être enregistré avec un nom, et pour la même insance vous avez besoin ContainerControlledLifeTimeManager () comme LifeTimeManager.
_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");
var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));
var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));
La réponse très courte est: non. L'unité n'a actuellement aucun moyen de passer des paramètres dans le constructeur qui ne sont pas constantes ou injecté, que j'ai pu trouver. À mon humble avis, c'est la plus grande chose qu'il manque, mais je pense qu'il est par la conception plutôt que par omission.
Comme le fait remarquer Jeff Fritz, vous pourriez en théorie créer un gestionnaire de vie personnalisé qui sait quelle instance contexte d'injecter dans divers types, mais qui est un niveau de codage en dur qui semble éviter le but d'utiliser l'unité ou DI dans le premier endroit.
Vous pouvez prendre un petit pas en arrière de la pleine DI et faire vos mises en œuvre du référentiel responsable de l'établissement de leurs propres contextes de données. Le contexte par exemple peut encore être résolu du conteneur, mais la logique de décider lequel utiliser devrait aller dans la mise en œuvre du référentiel. Ce n'est pas aussi pur, certes, mais il se débarrasser du problème.
Une autre alternative, vous pouvez utiliser (ne sais pas vraiment si elle est une bonne pratique ou non) est la création de deux conteneurs et l'enregistrement d'une instance pour chaque:
IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context
//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance
Espérons que cela aide aussi
NotDan, je pense que vous avez répondu à votre propre question dans les commentaires à lassevk.
D'abord, je voudrais utiliser un LifetimeManager pour gérer le cycle de vie et le nombre de cas de IDataContext que l'unité crée.
http://msdn.microsoft.com/en-us/library/cc440953. aspx
On dirait que l'objet ContainerControlledLifetimeManager
vous donnera la gestion de l'instance que vous avez besoin. Avec cette LifetimeManager en place, l'unité doit ajouter la même instance de la IDataContext à tous les objets qui nécessitent une dépendance IDataContext.