﻿# ASP.NET 如何動態載入組件(Assembly)

如果你的 IIS 中有許多相關站台、網站、或 Web，但每個不同的網站都會使用到相同組件的話，通常的作法是將該組件註冊進 [GAC](http://en.wikipedia.org/wiki/Global_Assembly_Cache) ( [Global Assembly Cache](http://en.wikipedia.org/wiki/Global_Assembly_Cache) )。我最近就在想有沒有辦法就將組件放在特定目錄下，然後所有的 ASP.NET 就動態載入這個目錄中的特定幾個共用的組件，以下是研究的心得分享。

我將整個過程分成「開發階段」與「部署階段」，並假設以下情境：

-   假設共用的組件檔名為 "**ShareCL.dll**"。
-   **部署階段**時要將 **ShareCL.dll** 放一份到特定目錄下，假設共用的目錄為 **"D:\\ShareDLL\\**"。

### 開發階段

在開發階段的時候，那些共用的組件一樣放到各專案的 bin 目錄下，所以在 Visual Studio 中開發的時候，一樣可以享用 Intellisense 的好處，整個開發過程就跟平常開發時一樣。

但由於我們將網站部署到正式主機時，組件並不在各網站的 bin 目錄下，而是在共用的目錄裡，這時就會發生組件解析失敗的錯誤：

> 無法載入檔案或組件 'ShareCL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 或其相依性的其中之一。 系統找不到指定的檔案。

我們只要修改 Global.asax 的 Application\_Start() 事件中的程式碼，告訴 AppDomain 在解析/找尋組件失敗的時候，要特別去我指定的地方載入共用的組件，我們要靠的是 [AppDomain.AssemblyResolve](http://msdn.microsoft.com/zh-tw/library/system.appdomain.assemblyresolve.aspx) 事件：

```
protected void Application_Start() {
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyAssemblyResolver);
}

static Assembly MyAssemblyResolver(object sender, ResolveEventArgs args) {
    AppDomain domain = (AppDomain)sender;
    byte[] rawAssembly = System.IO.File.ReadAllBytes(@"D:\ShareDLL\ShareCL.dll");
    byte[] rawSymbolStore = System.IO.File.ReadAllBytes(@"D:\ShareDLL\ShareCL.pdb");
    Assembly assembly = domain.Load(rawAssembly, rawSymbolStore);
    return assembly;
}
```

加上這段程式碼之後，當網站應用程式找不到我們的共享組件時，就會自動到 D:\\ShareDLL\\ShareCL.dll 動態載入組件了，而且也只有「找不到」組件時才會執行這個事件方法，因此並不會影響開發作業。

### 部署階段

部署網站時就可以不用再針對每個網站更新 bin 目錄下的組件了，只要將組件更新到共享的組件目錄中即可。

不過由於組件是在 Application-Level 載入的，所以就算你更新了網站中的組件，事實上也不會立即生效，而是當應用程式重新啟動時才會重新載入更新過的組件，這部分可以透過重新啟動 IIS 中的應用程式集區(Application Pool)即可達到此需求。

如果你想列出目前 AppDomain 所載入的組件有哪些，可以用以下程式碼取得：

```
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

foreach (Assembly assembly in assemblies)
{
    Response.Write(assembly.FullName + "<br/>");
}
```

**相關連結**

-   [AppDomain 類別](http://msdn.microsoft.com/zh-tw/library/system.appdomain.aspx)
-   [AppDomain.AssemblyResolve 事件](http://msdn.microsoft.com/zh-tw/library/system.appdomain.assemblyresolve.aspx)
-   [Global Assembly Cache - Wikipedia, the free encyclopedia](http://en.wikipedia.org/wiki/Global_Assembly_Cache)
-   [全域組件快取工具 (Gacutil.exe)](http://msdn.microsoft.com/zh-tw/library/ex0ss12c.aspx)
