2010-04-27 89 views
1

继续寻求一个好的插件实现,我一直在测试StructureMap程序集扫描特性。获取从基类继承的类型实例,实现接口,使用StructureMap

所有插件都将继承自抽象类PluginBase。这将提供对日志等常见应用程序服务的访问。根据它的功能,每个插件可能会实现其他接口,例如IStartUpTask。

我初始化我的插件,像这样:

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

我然后遇到的难点是如何对代码的接口(不是PluginBase)工作。这是很容易与PluginBase工作:

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

     foreach (var plugin in plugins) 
     { 

     } 

但具体功能(例如IStartUpTask.RunTask)是联系在一起的接口,而不是基类。

我很欣赏这可能不是特定于结构图(也许更多的是一个反思问题)。

感谢, 本

回答

2

你知道所有在注册时的特定接口的?如果是这样,您可以制定一个自定义注册约定,将其实现的接口的插件“族”注册到每个类型。一个IRegistrationConvention获取每种类型,一次一个。你可以做一个简单的检查,看看当前类型是否实现了所需的接口,如果是,添加它。

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

然后在后面的代码,你可以检索插件每个单独的专用接口:

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

这种方法允许你注入一个枚举您的自定义界面插件成为阶级的利益这需要他们,而不是拨打服务地点电话。

另外,如果你不想做一个登记约定,你可以使用便捷的OfType LINQ扩展方法做过滤在运行时:

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

@Joshua - OfType 方法正是我现在所需要的,完美的。我在运行时知道所有的接口,不过也会看到IRegistrationConvention。谢谢 – 2010-04-27 13:23:47

+0

@Joshua - 刚刚添加了一个自定义插件扫描器。我似乎没有对于().Add(type)函数可用? – 2010-04-27 13:41:59

+0

忽略上述内容 - 我使用的是旧版本的StructureMap。我现在已更新到最新版本。 – 2010-04-27 14:26:44

0

在情况下,它可以帮助别人,我也跟着约书亚的咨询和加入我自己的注册约定:

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); 
      } 
     } 
    } 
} 

我无法得到的。新增的方法来工作,不管是什么我试过了,所以只好用TheDefault.Is.OfConcreteType(类型)。

然后在我的引导程序,我扫描像这样:

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

我可以再抢我的IStartUp任务类型,像这样:

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

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

这就是说,对一些新的读了之后StructureMap的功能,我不确定我需要做以上任何事情。例如,我可以只改变我的扫描委托功能:

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

,并使用我的接口的具体类型(从PluginBase继承):

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

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

这两种方法似乎达到同样的事情。

相关问题