6

Je travaille sur une application WPF utilisant une architecture MVC et un conteneur IOC. Actuellement, je suis aux prises avec un problème de conception impliquant la portée et la durée de vie de certains composants fournis par le conteneur. Voici la situation.Comment mieux implémenter un cycle de vie à la vue pour les composants injectés par l'IoC?

Je vais généraliser en disant quelque peu incorrectement que les conteneurs IOC supportent deux cycles de vie de composants, singleton et transitoire. Mais nous avons besoin d'un terrain d'entente pour certains ensembles de composants.

Considérons une vue qui affiche une liste d'enregistrements dans une grille. Lorsque l'utilisateur clique sur un enregistrement, une nouvelle vue s'ouvre pour afficher les détails de l'enregistrement et permettre l'édition. L'utilisateur peut avoir plusieurs de ces vues ouvertes, chacune affichant un enregistrement différent. Chaque vue obtient son propre modèle et son propre contrôleur. Dans le contexte d'un ensemble modèle-vue-contrôleur donné, certains composants tels que les boîtes de dialogue sont à la fois transitoires et injectés paresseusement. C'est-à-dire que nous voulons une nouvelle instance chaque fois que nous avons besoin d'en afficher une et puisque la plupart de ces transitoires ne sont nécessaires que si l'utilisateur prend certaines mesures, nous injectons d'abord un délégué usine. Le délégué est ensuite appelé au besoin pour exécuter la résolution de dépendance réelle. Au-delà du modèle, de la vue et du contrôleur, il existe une multitude d'autres composants pour lesquels nous voulons une instance par jeu m-v-c. Par exemple, nous implémentons le modèle de conversation NHibernate qui appelle l'ouverture d'une session lorsque la vue s'ouvre et reste ouverte jusqu'à sa fermeture. De même, chaque ensemble a besoin de son propre courtier d'événements partagés et potentiellement de quelques "autres choses". Si toutes ces dépendances étaient résolues au moment de la création de la vue, cela ne poserait pas de problème. Nous pourrions les déclarer tous comme transitoires et être fait avec lui. Cependant, certaines de ces dépendances paresseusement résolues ont elles-mêmes des dépendances sur le modèle, le contrôleur ou les "autres choses". Le problème est donc que, lors de la résolution d'une dépendance paresseuse, le conteneur derrière le délégué doit injecter la bonne instance de chaque dépendance. Ceci implique bien sûr que le délégué lui-même est en quelque sorte lié à l'ensemble m-v-c, mais cela ne devrait pas être un problème si le problème plus large peut être résolu.

Maintenant, je disais que je simplifiais à l'excès la liste des cycles de vie supportés. La plupart des conteneurs prennent en charge certains cycles de vie intermédiaires, tels qu'un thread ou une pré-requête, ce qui permet d'établir une portée conceptuellement similaire à ce que nous recherchons. Cela ne s'applique pas dans un scénario d'interface utilisateur interactif. Ce n'est pas le cas que chaque vue est sur son propre fil ou dans un autre contexte pratique qui fournit la base de la portée.

Ainsi ma question est, quelle est la meilleure manière de mettre en application un cycle de vie de composant par vue (ou par n'importe quel contexte arbitraire) en utilisant un conteneur d'IOC. Notre conteneur actuel est l'unité, mais nous nous sommes suffisamment extirpés pour que nous puissions passer sans trop de difficultés. Donc, si cela est plus facilement mis en œuvre ou est implémenté hors de la boîte par un autre conteneur, nous pourrions envisager une commutation.

Répondre

4

Le motif que vous décrivez est l'unité de travail. Vous avez raison en ce qu'il est facilement défini pour les requêtes Web, mais incorrect en indiquant qu'il ne s'applique pas aux scénarios d'interface utilisateur interactive.La vue est lui-même le contexte de détermination de la portée - vous savez quand vous vous déplacez à et loin de là, et ce sont les points que vous créez respectivement et détruire les conteneurs enfants:

  1. Déplacer pour afficher
  2. Créer un enfant récipient pour une vue
  3. Resolve instance de vue du conteneur enfant
  4. Travaillez
  5. conteneur enfant Détruisez
  6. éloigner vue
+0

J'ai examiné cette possibilité, mais je ne suis pas clair sur la relation entre les conteneurs pour enfants et les cycles de vie des composants. Plus précisément, il semble que les différents conteneurs se comportent différemment à cet égard. Le conteneur Castle utilise les mêmes instances singleton sur tous les conteneurs de la même hiérarchie. Dans son nom, ContainerControlledLifetimeManager d'Unity implique le contraire, que chaque conteneur enfant reçoive un nouvel ensemble complet de tous les composants contrôlés par le conteneur. Il doit y avoir un autre gestionnaire de la vie qui est au milieu ... –

+0

Hah! Cela m'a fait penser à une nouvelle requête google à essayer et je viens de trouver le HierarchicalLifetimeManager (http://msdn.microsoft.com/en-us/library/ff660872(PandP.20).aspx). Cela ressemble à ce dont j'ai besoin. Merci! –

+0

@Kenneth: Je suis d'accord avec Bryan. L'astuce consiste à injecter une IUnitOfWorkFactory (ou déléguer si vous le souhaitez) dans le contrôleur et laisser ce contrôleur (ou quiconque contrôle la durée de vie de la session) créer une unité de travail en utilisant cette usine. Regardez par exemple à cet article: http://bit.ly/bF7jL3. – Steven