MongoCola 開發邁入第三年,官方 C# Driver 功能不足導致大量自研。近期著手開發外掛系統,讓社群貢獻擴充功能 (匯出、備份、分析等)。本文分享極簡外掛架構:基底類別、反射發現、動態選單、執行入口。
namespace MagicMongoDBTool.Common
{
public abstract class PlugBase
{
public enum PathLv : int
{
ConnectionLV = 0, // 連線/伺服器層級
InstanceLV = 1, // 實例層級
DatabaseLV = 2, // 資料庫層級
CollectionLV = 3, // 集合層級
DocumentLV = 4, // 文件層級
Misc = 9 // 雜項
}
public string PlugName = ""; // 選單顯示名稱
public string PlugFunction = ""; // 功能說明 (ToolTip)
public dynamic PlugObj; // 執行上下文物件 (由主程式注入)
public PathLv RunLv = PathLv.ConnectionLV; // 適用層級
public abstract int Run(); // 入口方法
}
}
RunLv 決定外掛在樹狀檢視的哪個層級顯示 (右鍵選單/工具列)。PlugObj 由主程式依 RunLv 注入對應物件 (MongoServer/MongoDatabase/MongoCollection 等)。MagicMongoDBTool.Common.dll),外掛專案參考即可。namespace MagicMongoDBTool.Module
{
public static class PlugIn
{
public static Dictionary PlugInList = new Dictionary();
public static void LoadPlugIn()
{
foreach (var file in Directory.GetFiles(Application.StartupPath + @"\PlugIn\", "*.dll"))
{
try
{
var asm = Assembly.LoadFile(file);
var fileName = Path.GetFileNameWithoutExtension(file);
if (fileName == "MagicMongoDBTool.Common") continue; // 跳過基底 DLL
var type = asm.GetType($"{fileName}.{fileName}"); // 慣例:命名空間.類別名 = 檔名.檔名
var ctor = type.GetConstructor(Type.EmptyTypes);
var plug = (PlugBase)ctor.Invoke(null);
PlugInList[fileName] = plug;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
}
}
關鍵點:Common.dll 必須置於主程式目錄 (而非 PlugIn 目錄),否則反射建構子時找不到基底類別定義。
PlugIn.LoadPlugIn();
foreach (var kv in PlugIn.PlugInList)
{
var item = new ToolStripMenuItem(kv.Value.PlugName)
{
ToolTipText = kv.Value.PlugFunction,
Tag = kv.Key
};
item.Click += (s, e) => RunPlugIn(kv.Key);
plugInToolStripMenuItem.DropDownItems.Add(item);
}
private void RunPlugIn(string key)
{
var asm = Assembly.LoadFile(Application.StartupPath + $@"\PlugIn\{key}.dll");
var type = asm.GetType($"{key}.{key}");
var plug = (PlugBase)type.GetConstructor(Type.EmptyTypes).Invoke(null);
// 依 RunLv 注入對應物件
switch (PlugIn.PlugInList[key].RunLv)
{
case PlugBase.PathLv.ConnectionLV:
case PlugBase.PathLv.InstanceLV:
plug.PlugObj = SystemManager.GetCurrentServer();
break;
case PlugBase.PathLv.DatabaseLV:
plug.PlugObj = SystemManager.GetCurrentDataBase();
break;
case PlugBase.PathLv.CollectionLV:
plug.PlugObj = SystemManager.GetCurrentCollection();
break;
case PlugBase.PathLv.DocumentLV:
// plug.PlugObj = ...;
break;
}
plug.Run();
}
using MagicMongoDBTool.Common;
using MongoDB.Driver;
using System.Windows.Forms;
namespace ExportToExcel
{
public class ExportToExcel : PlugBase
{
private IMongoCollection _collection;
public ExportToExcel()
{
RunLv = PathLv.CollectionLV;
PlugName = "匯出至 Excel";
PlugFunction = "將目前集合資料匯出為 Excel 檔案";
}
public override int Run()
{
_collection = (IMongoCollection)PlugObj;
MessageBox.Show($"準備匯出集合: {_collection.CollectionNamespace.CollectionName}");
// 實際匯出邏輯...
return 0;
}
}
}
不到 200 行核心代碼即可構建功能完整的外掛系統,關鍵在於基底類別契約、約定優於配置的命名慣例、反射延遲載入。歡迎 MongoDB 愛好者 Fork 專案、開發實用外掛,共建生態。