模組化將大型系統拆分為功能單一、自包含的子系統,提升獨立開發、測試與重用性。核心原則包括:
實作 IModule 介面即為一個模組,通常獨立為一個專案,內部常採 MVP/MVC 模式。IModule 僅定義 Initialize() 方法,由 ModuleLoader 載入時調用。
透過建構子注入取得 IUnityContainer、IRegionManager 等服務,並在 Initialize 中註冊視圖與服務:
public class NewsModule : IModule {
private readonly IUnityContainer _container;
public NewsModule(IUnityContainer container) { _container = container; }
public void Initialize() { RegisterViewsAndServices(); }
protected void RegisterViewsAndServices() {
_container.RegisterType<INewsFeedService, NewsFeedService>(new ContainerControlledLifetimeManager());
}
}
重寫 Bootstrapper.GetModuleEnumerator(),將模組類型加入 StaticModuleEnumerator。缺點:Shell 專案需引用所有模組、啟動即全載入、異動需重新編譯。
protected override IModuleEnumerator GetModuleEnumerator() {
return new StaticModuleEnumerator()
.AddModule(typeof(MyModule1))
.AddModule(typeof(MyModule2));
}
使用 DirectoryLookupModuleEnumerator 掃描指定目錄下實作 IModule 的類型。需以 [Module]、[ModuleDependency] Attribute 標註模組名稱與相依順序,避免循環相依。
[Module(ModuleName = "ModuleA")] public class ModuleA : IModule { ... }
[Module(ModuleName = "ModuleB")] [ModuleDependency("ModuleA")] public class ModuleB : IModule { ... }
protected override IModuleEnumerator GetModuleEnumerator() {
return new DirectoryLookupModuleEnumerator(@".\Modules");
}
使用 ConfigurationModuleEnumerator 解析 *.config 中 <modules> 區段,依 dependency 順序載入。優點:修改配置即可增刪替換模組,無需重新編譯。
<modules>
<module assemblyFile="Modules/ModuleA.dll" moduleType="ModuleA.ModuleA" moduleName="ModuleA" />
<module assemblyFile="Modules/ModuleB.dll" moduleType="ModuleB.ModuleB" moduleName="ModuleB">
<dependencies><dependency moduleName="ModuleA"/></dependencies>
</module>
</modules>
無論掃描資料夾或配置檔,列舉出的模組預設啟動即載入。可設定 startupLoaded="false",運行時以程式碼手動載入:
<module ... startupLoaded="false" />
// 運行時
moduleLoader.Initialize(moduleEnumerator.GetModule("ModuleC"));
優點:降低啟動時間與記憶體佔用。
Shell 與模組專案輸出目錄不同,需在模組專案 Post-build event 加入 xcopy 指令自動複製至 Shell 的 bin\Modules 目錄:
xcopy "$(TargetDir)*.*" "$(SolutionDir)ShellProject\bin\$(ConfigurationName)\Modules\" /Y