2010-04-27 9 views
1

Poursuivant ma quête d'une implémentation de plug-in de qualité, j'ai testé les fonctionnalités d'analyse de l'assemblage de StructureMap.Obtenir une instance de type héritant de la classe de base, implémentation de l'interface, en utilisant StructureMap

Tous les plugins héritent de la classe abstraite PluginBase. Cela permettra d'accéder aux services d'application courants tels que la journalisation. Selon sa fonction, chaque plugin peut alors implémenter des interfaces supplémentaires, par exemple, IStartUpTask.

Je suis mes plugins comme en cours d'initialisation si:

  Scan(x => { 
      x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"), 
       assembly => assembly.GetName().Name.Contains("Extension"));    
      x.AddAllTypesOf<PluginBase>(); 
     }); 

La difficulté que je suis d'avoir ensuite est de savoir comment travailler sur l'interface (pas PluginBase) dans le code. Il est assez facile de travailler avec PluginBase:

  var plugins = ObjectFactory.GetAllInstances<PluginBase>(); 

     foreach (var plugin in plugins) 
     { 

     } 

Mais des fonctionnalités spécifiques (par exemple IStartUpTask.RunTask) est liée à l'interface, pas la classe de base.

J'apprécie que cela ne soit pas spécifique à structuremap (peut-être plus une question de réflexion).

Merci, Ben

Répondre

2

Connaissez-vous toutes les interfaces spécifiques au moment de l'enregistrement? Si c'est le cas, vous pouvez créer une convention d'enregistrement personnalisée qui enregistre chaque type avec le plugin "family" de l'interface qu'il implémente. Une IRegistrationConvention obtient chaque type, un à la fois. Vous pouvez faire une vérification simple pour voir si le type actuel implémente l'interface désirée, et si c'est le cas, ajoutez-le.

if (typeof(IStartUpTask).IsAssignableFrom(currentType)){ 
    For<IStartUpTask>().Add(currentType); 
} 

Puis, plus tard dans le code, vous pouvez récupérer des plugins pour chaque interface spécifique individuellement:

var startupTasks = ObjectFactory.GetAllInstances<IStartUpTask>(); 

Cette approche a l'avantage de vous permettre d'injecter un dénombrable de vos plug-ins d'interface personnalisés dans une classe qui a besoin d'eux, au lieu de faire l'appel de l'emplacement de service.

Sinon, si vous ne voulez pas faire une convention d'inscription, vous pouvez juste faire le filtrage lors de l'exécution en utilisant la méthode d'extension OfType LINQ pratique:

var startupTasks = ObjectFactory.GetAllInstances<PluginBase>().OfType<IStartupTask>(); 
+0

@Joshua - la méthode OfType fait exactement ce dont j'ai besoin pour l'instant, parfait. Je connais toutes les interfaces au moment de l'exécution, donc je vais me pencher sur la IRegistrationConvention. Merci –

+0

@Joshua - vient d'ajouter un scanner plugin personnalisé. Je ne semble pas avoir la fonction For () .Add (type) disponible? –

+0

Ignorer ce qui précède - J'utilisais une ancienne version de StructureMap. J'ai maintenant mis à jour à la dernière version. –

0

Dans le cas où il aide les autres, je suivais Joshua des conseils et a ajouté ma propre convention d'inscription:

public class PluginConvention : IRegistrationConvention 
{ 
    public void Process(Type type, Registry registry) { 
     if (type.BaseType == null) return; 

     if (type.BaseType.Equals(typeof(PSAdmin.Core.Domain.PluginBase))) { 
      if (typeof(IStartUpTask).IsAssignableFrom(type)) { 
       registry.For<IStartUpTask>() 
        .TheDefault.Is.OfConcreteType(type); 
      } 
     } 
    } 
} 

Je ne pouvais pas la méthode .Add de travailler, peu importe ce que j'ai essayé, donc dû utiliser TheDefault.Is.OfConcreteType (type).

Puis dans mon bootstrapper je suis à balayage comme ceci:

 Scan(x => { 
      x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"), 
       assembly => assembly.GetName().Name.Contains("Extension")); 
      x.Convention<PluginConvention>(); 
     }); 

Je peux alors saisir mes types de tâches Idémarrage comme ceci:

 var plugins = ObjectFactory.GetAllInstances<IStartUpTask>();    

     foreach (var plugin in plugins) 
     { 
      plugin.Configure(); 
     } 

Cela dit, après avoir lu sur certains des nouveaux caractéristiques de StructureMap, je ne suis pas sûr que j'ai besoin de faire tout ce qui précède.Par exemple, je pouvais changer ma fonction de délégué Scan to:

 Scan(x => { 
      x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"), 
       assembly => assembly.GetName().Name.Contains("Extension")); 
      x.AddAllTypesOf<PluginBase>(); 
     }); 

Et utiliser mon interface types de béton (héritant de PluginBase):

 var tasks = ObjectFactory.Model.GetAllPossible<IStartUpTask>(); 

     foreach (var task in tasks) 
     { 
      task.Configure(); 
     } 

Les deux méthodes semblent réaliser la même chose.