2009-09-22 5 views
2

J'essaie d'autoriser mes composants de logique métier à rechercher des services lorsqu'ils sont ajoutés à l'une de mes classes de formulaire/contrôle. Par exemple, je pourrais avoir une classe ClientManager dans ma bibliothèque, qui encapsule une certaine logique métier. Il nécessite une instance ILoginManager pour rechercher des données dont il a besoin pour fonctionner. L'instance ILoginManager concrète est créée dans l'application WinForms, par exemple en tant que singleton. Je voudrais être en mesure de déposer un composant ClientManager sur un formulaire, ce qui rendrait l'instance ILoginManager disponible pour le composant automatiquement.Comment utiliser l'implémentation du localisateur de service dans System.ComponentModel pour l'injection de dépendances dans une application WinForms?

D'après ce que je comprends this article on lightweight containers, je pourrais le faire en utilisant GetService:

public class ClientManager : Component 
{ 
    public ClientManager() {} 
    public ClientManager(IContainer container) { 
     container.Add(this); 
    } 

    public ILoginManager User 
    { 
     // would really be cached in a private field 
     get { return GetService(typeof(ILoginManager)) as ILoginManager; } 
    } 

    // does something that requires the User property to be set 
    public void DoSomething(); 
} 

je serais alors un conteneur qui l'emporte sur GetService pour retourner mon exemple:

public class MyContainer : Container 
{ 
    ServiceContainer svc; 

    public MyContainer() { 
     svc = new ServiceContainer(); 
     svc.AddService(typeof(ILoginManager), GlobalAppStuff.LoginManager); 
    } 

    protected override object GetService(Type service) { 
     return svc.GetService(service); 
    } 
} 

En tant que autonome solution, cela fonctionne bien, mais je ne peux pas comprendre comment l'intégrer dans un contrôle désignable, puisque le concepteur génère toujours un conteneur par défaut System.ComponentModel.Container, et je ne connais aucun moyen d'y injecter des services.

La documentation MSDN est vague dans la description de la façon dont ces concepts doivent être réellement utilisés. Existe-t-il un moyen simple de le faire en utilisant les classes ComponentModel qui est convivial?

Répondre

2

N'utilisez pas System.IServiceProvider pour DI - il est principalement conçu pour une utilisation au moment de la conception. Pour les implémentations IComponent, le concepteur VS affectera une valeur à la propriété Site, ce qui permet à l'ensemble du mécanisme IServiceProvider de fonctionner, mais cette propriété sera nulle au moment de l'exécution, ce qui signifie que tous vos appels à GetService échoueront .

Vous seriez mieux d'utiliser un bon DI conteneurs, comme le château de Windsor, StructureMap etc.

+1

Castle ne me permet pas de glisser mes composants à une forme car il utilise l'injection de constructeur. StructureMap utilise un objet statique que je n'aime pas car il lie mes objets spécifiquement à StructureMap. Il semble que les composants .NET de base supportent déjà la plupart de ce dont j'ai besoin, c'est juste la peine de le faire fonctionner avec le concepteur. –

+0

Peut-être, mais même si c'est difficile, cela ne fonctionnera que * dans * le concepteur. IComponent.Site sera null au moment de l'exécution, mais c'est cette valeur ISite qui fournit l'implémentation IServiceProvider, donc cela ne fonctionnera pas au moment de l'exécution. –

+0

Je ne suis pas sûr si c'est tout ce qu'il ya à faire. Le concepteur ne définit pas ISite - le conteneur fait. Le concepteur utilise son propre conteneur System.ComponentModel.Design.DesignerHost au moment du design. On devrait être en mesure de fournir son propre conteneur à l'exécution, et Visual Studio génère du code pour cela, mais je ne sais pas comment remplacer le type de conteneur qu'il génère. –

Questions connexes