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

分享到噗浪!

如果你的 IIS 中有許多相關站台、網站、或 Web,但每個不同的網站都會使用到相同組件的話,通常的作法是將該組件註冊進 GAC ( 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 事件:

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/>");
}

相關連結

  

此文章由 will 發表於 2008/12/28 下午 09:49:19

永久連結 | 評論 (6) | 此文章的RSSRSS comment feed |

分類: .Net | ASP.NET

標籤: ,

評論

十二月 29. 2008 09:49

blogger

那請問一下
如果我所有的要用到的組件
都不在 GAC 也不在 BIN 下面
全都放在 ShareDLL 目錄
也可以這樣用嗎?
另外如果是 WinForm Application 的話
是否也採取一樣的做法?
謝謝您的文章
好多都很受用唷 Laughing

blogger 台灣

十二月 29. 2008 10:20

will

1. 可以啊!

2. WinForm Application 與 Console Application 我也曾經嘗試過,但好像動態載入的組件都一定要透過 Reflection 才能使用,沒辦法像 ASP.NET 這麼方便的樣子。
我有到 MSDN 討論區發問,看看這幾天會不會有人回答:http://tinyurl.com/a63ltr

will 台灣

一月 4. 2009 23:41

tomexou

msdn論壇有兩位回文,第1則講plugin方式,但它僅觸發單一method而己,不符合這題目的載入動作。第2則講dll的路徑,說loadfrom與loadfile的不同,我試了一下也沒用。google上的文章大都講動態觸發單一method的方式,直到現在,我還沒發現真正的解答。

tomexou 台灣

二月 8. 2010 16:18

James

請問Will大你覺得使用這個方法的優勢在那裡?

我不曉得有什麼理由需要特別將組件從BIN移到GAC或是特定資料夾。

組件可以放在下面三種地方:
1.組件放在各專案的bin資料夾下
2.組件註冊在GAC
3.動態載入組件(此篇介紹)

我個人認為組件放在這三個地方的優缺點如下:
1.組件放在各專案的bin資料夾下:
優點:
(1)開發階段
建置方式簡單,無需另外設定。

(2)部署階段
部置方式簡單,無需另外設定,只要將開發階段的程式直接複製到IIS下就可以執行;而且組件複製到BIN資料夾下會造成IIS重開,組件會立即生效。

缺點:
(1)開發階段
與其它兩個方法比較起來,似乎沒有特別的缺點。

(2)部署階段
假如組件更新的話,要各別更新同一個伺服器上各個WEB專案的BIN資料夾下組件。

2.組件註冊在GAC:
優點:
(1)開發階段
沒有特別的優點。

(2)部署階段
同一個伺服器上的所有網站若使用同一個組件,只要更新GAC上的組件就讓所有網站更新組站。

缺點:
(1)開發階段
需要由每個開發者自行將組件註冊到GAC,多了一件工作。

(2)部署階段
不曉得更新了GAC上的組件是否也要重開IIS才會生效?
每次都要重新在GAC註冊。

3.動態載入組件(此篇介紹)
優點:
(1)開發階段
沒有特別的優點。

(2)部署階段
同一個伺服器上的所有網站若使用同一個組件,只要更新特定資料夾上的組件就讓所有網站更新組站。但是與GAC方法比較起來的優點是什麼?

缺點:
(1)開發階段
需要多寫一段Code。

(2)部署階段
與GAC方法比較,必須多寫一段Code。
與BIN方法比較,需重新啟動 IIS 中的應用程式集區才能使更新後的組件生效。

James 台灣

二月 8. 2010 18:33

Will 保哥

James:

感謝您的分析,我認為使用這個方法的好處僅用在以下條件成立時:

1. 不知道何謂 GAC 或不知道如何將自己的組件安裝至 GAC
2. 有多個站台或 Web Application 需要共用組件,而不希望複製各組件到各站台下的 bin 目錄

而我當時主要目的是想學習 ASP.NET 載入組件的過程而已,其實沒啥實用價值,這個技巧我連一次都沒用過,只用作研究用途罷了,呵~

不過,誰知道日後會不會用上呢?!^_^

Will 保哥 台灣

二月 8. 2010 18:35

Will 保哥

另外,若用此法與更新組件至 bin 目錄相比還有個優點:

用此法更新組件時不會導致 Web 應用程式「自動重啟」,你可以等應用程式集區「自然回收」時自動重新載入新版組件,在更版時不會影響現有網站的運作。

Will 保哥 台灣

新增評論


( 您輸入的Email不會顯示於網站上 )

  Country flag

biuquote
  • 評論
  • 線上預覽
Loading