技巧:使用可擴展對象模式擴展HttpApplication

接口:IExtensibleObject、IExtension和IExtensionCollection,這是可擴展對象模式中最重要的三個接口,也只有這三個接口。

IExtensibleObject自然是定義了可擴展對象,即我們要對誰進行擴展,它的定義非常簡單,僅僅是提供了一個只讀的屬性Extensions,用來提供所有擴展對象的集合,如下代碼所示:
public interface IExtensibleObject<T> where T : IExtensibleObject<T>
{
    IExtensionCollection<T> Extensions { get; }
}
IExtension定義了擴展對象的契約,使對象可以通過聚合擴展另一個對象(此處的另一個對象,就是指上面所講的擴展宿主IExtensibleObject),在IExtension中定義了兩個非常重要的方法Attach和Detach方法,分別用來提供聚合或解聚的通知。
public interface IExtension<T> where T : IExtensibleObject<T>
{
    void Attach(T owner);
    void Detach(T owner);
}
當一個擴展對象IExtension附加到可擴展對象的擴展集合中時,它的Attach方法將會被調用;反之如果從集合中移除一個擴展對象時,它的Detach方法會被調用。這一點我們可以通過Reflector來得到驗證,如下代碼所示:
protected override void InsertItem(int index, IExtension<T> item)
{
    lock (base.SyncRoot)
    {
        item.Attach(this.owner);
        base.InsertItem(index, item);
    }
}
protected override void RemoveItem(int index)
{
    lock (base.SyncRoot)
    {
        base.Items[index].Detach(this.owner);
        base.RemoveItem(index);
    }
}
最後一個接口是IExtensionCollection,它是IExtension對象的集合。

對HttpApplication進行擴展

下面我們就看一下如何使用可擴展對象模式對HttpApplication進行擴展,首先定義可擴展對象,讓ExtensibleHttpApplication派生於HttpApplication,並實現了IExtensibleObject接口,泛型的參數類型就是它自身,如下代碼所示:
public class ExtensibleHttpApplication : HttpApplication,
    IExtensibleObject<ExtensibleHttpApplication>
{
    private IExtensionCollection<ExtensibleHttpApplication> _extensions;
    
    public ExtensibleHttpApplication()
    {
        this._extensions = new ExtensionCollection<ExtensibleHttpApplication>(this);
    }
    public IExtensionCollection<ExtensibleHttpApplication> Extensions
    {
        get
        {
            return this._extensions;
        }
    }
}
有了可擴展的HttpApplication之後,需要在HttpApplication中實現任何功能,都可以作爲一個擴展附加到ExtensibleHttpApplication上去,如實現ASP.NET MVC路由,可以定義一個如下代碼所示的擴展對象:
public class MvcHttpApplication : IExtension<ExtensibleHttpApplication>
{
    public void Attach(ExtensibleHttpApplication owner)
    {
        RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        RouteTable.Routes.MapRoute(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
        );
    }
    public void Detach(ExtensibleHttpApplication owner)
    {
        //nothing
    }
}
同樣如果要在HttpApplication中啓動Workflow,可以再針對Workflow定義一個擴展對象,如下示例代碼所示:
public class WorkflowHttpApplication : IExtension<ExtensibleHttpApplication>
{
    private WorkflowRuntime workflowRuntime;
    public void Attach(ExtensibleHttpApplication owner)
    {
        workflowRuntime = new WorkflowRuntime("workflowServicesConfig");
        ExternalDataExchangeService externalDataExchangeService = new ExternalDataExchangeService();
        workflowRuntime.AddService(externalDataExchangeService);
        workflowRuntime.StartRuntime();
    }
    public void Detach(ExtensibleHttpApplication owner)
    {
        workflowRuntime.StopRuntime();
    }
}
我們已經定義好了相應的擴展對象,只需要在相應的HttpApplication把擴展對象附加到ExtensibleHttpApplication上即可,修改Global.asax中的代碼如下所示:
public class MvcApplication : ExtensibleHttpApplication
{
    protected void Application_Start()
    {
        this.Extensions.Add(new MvcHttpApplication());
        this.Extensions.Add(new WorkflowHttpApplication());
    }
}
現在代碼是不是看起來優雅多了?現在如果要在Application_Start中,添加另外一些執行代碼,只需要編寫相應的擴展對象,並將其添加到Extension集合中即可。也許有朋友會問,這樣每添加一些新的代碼,還是要修改Application_Start中的代碼啊?別忘了,可以通過配置可以解決這個問題,WCF中的擴展不也是可以採用配置方式實現,不是嗎?同樣,如果我們需要在Application_End事件中釋放某些對象,可以直接從擴展集合中移除它,此時將會調用它的Detach方法。

總結

本文介紹瞭如何使用WCF中提供的可擴展對象模式擴展HttpApplication,事實上可擴展對象模式的作用遠不在此,它可以擴展.NET類庫中任何我們想對其進行擴展的對象,或者是一個自定義的類型,都可以使用可擴展對象模式對其進行擴展。
特別鳴謝:Jesse Qu
注1:由於TerryLee最近一段時間忙於別的事務,無暇顧及Blog,所以有大量的評論和E-mail都沒能回覆,請大家見諒。
注2:由TerryLee撰寫的《Silverlight 2完美征程》一書,即將於本月底上市,敬請期待,詳情大家可以訪問本書官方網站[url]http://www.dotneteye.cn/silverlight[/url]瞭解。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章