專案採用 **工廠模式 + 反射 + 快取** 動態建立 DAL 實例:
// 設定檔
// 工廠核心代碼
string path = ConfigurationManager.AppSettings["DAL"]; // "SmsSystem.SQLServerDAL"
object obj = Assembly.Load(path).CreateInstance(cacheKey); // 拋 FileNotFoundException
異常:`FileNotFoundException: 未能載入檔案或組件 "SmsSystem.SQLServerDAL" 或其某一相依性。系統找不到指定的檔案。`
string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SmsSystem.SQLServerDAL.dll");
Assembly asm = Assembly.LoadFrom(dllPath); // 或 LoadFile (不載入相依性上下文)
object obj = asm.CreateInstance("SmsSystem.SQLServerDAL.CustEmployee"); // 完整型別名稱
⚠️ `LoadFrom` 會進入 **LoadFrom 上下文**,可能導致同一組件載入多份 (如本文後續暫存檔衝突)。**優先用 `Assembly.Load` + 正確組件名稱**。
錯誤:
類型 "SmsSystem.BLL.CustEmployee" 同時存在於 `Temporary ASP.NET Files\...\BLL.DLL` 和 `Temporary ASP.NET Files\...\SmsSystem.BLL.DLL` 中。
public static class DalFactory
{
private static readonly ConcurrentDictionary _cache = new();
private static readonly string _assemblyName = ConfigurationManager.AppSettings["DalAssembly"]; // 組件名稱
private static readonly string _namespace = ConfigurationManager.AppSettings["DalNamespace"]; // 命名空間前綴
public static T Create() where T : class
{
string cacheKey = typeof(T).FullName; // 介面完整名稱作為 Key
return (T)_cache.GetOrAdd(cacheKey, _ => CreateInstance());
}
private static T CreateInstance()
{
string typeName = $"{_namespace}.{typeof(T).Name.Substring(1)}"; // IUserDal → UserDal
try
{
// 1. 載入組件 (依組件名稱,需與專案 Assembly Name 一致)
Assembly asm = Assembly.Load(_assemblyName);
// 2. 建立實例 (依完整型別名稱)
object instance = asm.CreateInstance(typeName, true, BindingFlags.CreateInstance, null, null, null, null);
if (instance is T t) return t;
throw new InvalidOperationException($"型別 {typeName} 不實作 {typeof(T)}");
}
catch (Exception ex)
{
Log.Error(ex, $"建立 DAL 實例失敗: {typeName}");
throw new DalFactoryException($"無法建立 {typeof(T).Name} 實例", ex);
}
}
}
| 檢查項目 | 正確標準 |
|---|---|
| 專案 Assembly Name | 與設定檔 `DalAssembly` 完全一致 (含大小寫) |
| 輸出 DLL 檔名 | `AssemblyName.dll` |
| 實作類別完整名稱 | `{Namespace}.{ClassName}` (如 `SmsSystem.SQLServerDAL.UserDal`) |
| 介面與實作專案分離 | 介面在 `.IDAL`,實作在 `.SQLServerDAL` / `.MySqlDAL` |
| `bin/` 目錄無殘留舊 DLL | 每次建置前 Clean 或 CI 流程自動清理 |
| 暫存檔無舊版本 | 部署腳本包含清理 Temporary ASP.NET Files |
反射動態建立實例**核心前提:組件名稱 (Assembly Name) 與設定檔、專案屬性、輸出 DLL 三者完全一致**。`Assembly.Load` 載入的是**組件身分**,而非檔案路徑。**修改 Assembly Name 後必須徹底清理 `bin/`、`obj/` 與 ASP.NET 暫存目錄**,否則殘留舊 DLL 導致型別身分衝突。封裝統一的 `DalFactory`,集中管理組件名稱、命名空間慣例、快取與異常處理,是企業級專案的標準做法。