研究NuGet Server過程發現的新東西,不修改Global.asa就能加入Application_Start()/Appliation_Shutdown()事件的新做法---WebActivator!!

這是微軟NuGet開發小組成員David Ebbo所寫的一個程式模組,實現不修改Global.asa就加入Application_Start()/Shutdown()事件,目的在解決網站專案安裝程式庫的一項難題。部分程式庫有在Application_Start()階段加入初始化程序的需求,例如: 讀取設定檔、建立共用物件、處理Assembly參照... 等,一但引用時漏了此步驟,便會導致運作不正常。(我永遠記得第一次玩log4net的情景,就因忘了加Application_Start(),大半天搞不出來氣到想咬人,最後找到91這篇同病相憐的KB才頓然開悟)

安裝程式元件還需要修改Application_Start()才能使用,或多或少提高安裝複雜度,同時也增加安裝失敗的可能(以log4net為例,至少有兩個人跌倒過 XD)。而對NuGet自動安裝來說,自動修改Global.asa加入Application_Start()不但困難,而且還可能搞壞原本程式邏輯,因此最理想的做法在程式元件內部涵蓋這段邏輯,不要勞煩安裝程序或開發人員動手。透過在網站引用WebActivator.dll及在元件程式中加入適當的宣告,就能實現這種不沾手式的事件掛載法。(註: 但要ASP.NET 4.0才支援)

想當然爾,David是NuGet開發者,取得WebActivator的最簡單方法就是搓搓神燈,Add Library Package Reference並輸入webactivator。

為了示範WebActivator的效果,我建了一個ASP.NET Web Site Project及Class Library Project,網站專案參照MyClass程式庫,使用BooClass顯示一個ASP.NET Appication變數,而這個變數則需在Application_Start時加入。

為了做到這點,我們要在MyClass裡宣告一個靜態物件InitWork,並用WebActivator Attribute指定其中的Init()。WebActivator提供PreApplicationStartMethod、PostApplicationStartMethod、ApplicationShutdownMethod三種觸發時機,依實測,存取HttpContext.Current.Application的程式要放在PostApplicationStartMethod才能正確執行。因為MyClass與網站都要用到WebActivator,記得在兩個專案裡都要用Add Library Package Reference安裝WebActivator程式包,Web則要參照MyClass。

MyClass的Class1.cs程式碼如下: ([assembly: WebActivator.PostApplicationStartMethod…]是整個Assembly層級的宣告,也可選擇放在Assembly.cs中)

using System;
using System.Web;
 
//在Assembly層次宣告會自動在Application_Start()後接著執行的作業
[assembly: WebActivator.PostApplicationStartMethod(typeof(MyClass.InitWork), "Init")]
namespace MyClass
{
    //宣告一個靜態類別,提供一個靜態方法供Application_Start()之後接連觸發
    public static class InitWork
    {
        public static void Init()
        {
            //在Application["SECRET"]中加入一段廢話當作示範
            HttpContext.Current.Application.Add("SECRET", "Darkthread Rocks!");
        }
    }
    //測試用的類別
    public class BooClass
    {
        //測試用的方法,傳回Application_Start()塞入的無聊文字
        public string ShowSecret()
        {
            return Convert.ToString(HttpContext.Current.Application["SECRET"]);
        }
    }
}

在Web Application中隨便寫段Default.aspx.cs,測試Darkthread Rocks!可順利顯示,證明了我們真的做到不更動Global.asa就加入Application_Start(),簡化了引用元件時的安裝程序!

protected void Page_Load(object sender, EventArgs e)
{
    MyClass.BooClass boo = new BooClass();
    Response.Write(boo.ShowSecret());
    Response.End();
}

補充: 其實ASP.NET 4.0就已內建PreApplicationStartMethodAttribute(Phil Haack有篇介紹,事實上WebActivator也是靠它才能運作),功能十分相近但有些限制,一是整個Web Application只能掛載一次(如果多個元件都有自己的初始事件就沒辦法),二是它只提供Appilcation_Start()前觸發的選項,相較之下,WebActivator彈性大應用起來方便許多。


Comments

# by 阿尼

讚!

# by 大估

原來大家都有被log4Net的設定方式,搞的快發瘋的經驗…XD

Post a comment