2010-04-27 172 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(); 
     } 

這兩種方法似乎達到同樣的事情。