web-dev-qa-db-fra.com

Puis-je transmettre des paramètres de constructeur à la méthode Resolve () d'Unity?

J'utilise Unity de Microsoft pour l'injection de dépendances 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 ont tous deux un constructeur qui prend un paramètre IDataContext, et je veux que Unity initialise le référentiel avec le contexte que je lui passe. Notez également que IDataContext n'est pas enregistré avec Unity (je ne veux pas de 3 instances de IDataContext).

85
NotDan

À ce jour, ils ont ajouté cette fonctionnalité:

C'est dans la dernière goutte ici:

http://unity.codeplex.com/SourceControl/changeset/view/33899

Discussion à ce sujet ici:

http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434

Exemple:

container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
70
Exist

<2 cents>

Et si vous décidez plus tard d'utiliser un service différent qui nécessite plus ou moins que le contexte?

Le problème avec les paramètres du constructeur et l'IoC est que les paramètres sont finalement liés au type de béton utilisé, par opposition à faire partie du contrat défini par l'interface de service.

Ma suggestion serait que vous résolviez également le contexte, et je crois qu'Unity devrait avoir un moyen pour vous d'éviter d'en construire 3 instances, ou vous devriez envisager un service d'usine qui a un moyen pour vous de construire l'objet.

Par exemple, que se passe-t-il si vous décidez par la suite de construire un référentiel qui ne repose pas du tout sur une base de données traditionnelle, mais à la place, utilisez un fichier XML pour produire des données factices pour le test? Comment feriez-vous pour fournir le contenu XML à ce constructeur?

L'IoC est basé sur le découplage du code, en liant le type et la sémantique des arguments aux types concrets, vous n'avez vraiment pas fait le découplage correctement, il y a toujours une dépendance.

"Ce code peut éventuellement communiquer avec n'importe quel type de référentiel, tant qu'il implémente cette interface .... Oh, et utilise un contexte de données".

Maintenant, je sais que d'autres conteneurs IoC prennent en charge cela, et je l'avais également dans ma première version, mais à mon avis, cela n'appartient pas à l'étape de résolution.

</ 2 cents>

Merci les gars ... le mien est similaire au post de "Exist". Voir ci-dessous:

        IUnityContainer container = new UnityContainer();
        container.LoadConfiguration();

        _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
        {
            new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
        });
7
Kwex

Vous pouvez utiliser InjectionConstructor/InjectionProperty/InjectionMethod selon votre architecture d'injection dans le ResolvedParameter <T> ("nom") pour obtenir une instance d'un objet préenregistré dans le conteneur.

Dans votre cas, cet objet doit être enregistré avec un nom et, pour la même assurance, vous avez besoin de 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")));
5
Trecenti

La réponse très courte est: non. Unity n'a actuellement aucun moyen de transmettre au constructeur des paramètres qui ne sont pas constants ou injectés, que j'ai pu trouver. À mon humble avis, c'est la chose la plus importante qui manque, mais je pense que c'est par conception plutôt que par omission.

Comme le note Jeff Fritz, vous pouvez en théorie créer un gestionnaire de durée de vie personnalisé qui sait quelle instance de contexte injecter dans différents types, mais c'est un niveau de codage en dur qui semble éviter le but d'utiliser Unity ou DI en premier lieu.

Vous pouvez prendre un peu de recul par rapport à la DI complète et confier à vos implémentations de référentiel la responsabilité d'établir leurs propres contextes de données. Le contexte instance peut toujours être résolu à partir du conteneur, mais la logique pour décider lequel utiliser devra entrer dans l'implémentation du référentiel. Ce n'est pas aussi pur, certes, mais cela éliminerait le problème.

3
Neil Hewitt

Une autre alternative que vous pourriez utiliser (je ne sais pas vraiment si c'est une bonne pratique ou non) consiste à créer deux conteneurs et à enregistrer une instance pour chacun:

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

j'espère que cela aide aussi

1
Samuel Carrijo

NotDan, je pense que vous avez peut-être répondu à votre propre question dans les commentaires à lassevk.

Tout d'abord, j'utiliserais un LifetimeManager pour gérer le cycle de vie et le nombre d'instances d'IDataContext créées par Unity.
http://msdn.Microsoft.com/en-us/library/cc440953.aspx

Il semble que l'objet ContainerControlledLifetimeManager vous fournisse la gestion d'instance dont vous avez besoin. Avec ce LifetimeManager en place, Unity doit ajouter la même instance de IDataContext à tous les objets qui nécessitent une dépendance IDataContext.

0
Jeff Fritz