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

作者: TerryLee  來源: 博客園  發布時間: 2010-09-08 15:01  閱讀: 2025 次  推薦: 1   原文鏈接   [收藏]  
摘要:本文介紹了如何使用WCF中提供的可擴展對象模式擴展HttpApplication,事實上可擴展對象模式的作用遠不在此,它可以擴展.NET類庫中任何我們想對其進行擴展的對象,或者是一個自定義的類型,都可以使用可擴展對象模式對其進行擴展。

  概述

  HttpApplication對象對于做ASP.NET開發的朋友,我想沒有人不熟悉它。在ASP.NET開發中,經常避免不了要在HttpApplication中執行一些操作,如使用了ASP.NET MVC框架,就會在Application_Start 事件中避免不了這樣的路由規則配置代碼:

protected void Application_Start()
{
    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
    );
}

  如果僅僅是這一條,看起來倒不覺的有什么問題,但如果同時在應用程序中使用了工作流,又避免不了在Application_Start出現啟動工作流運行時的代碼:

protected void Application_Start()
{
    // 注冊路由規則
    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
    );

    // 啟動工作流
    WorkflowRuntime workflowRuntime = new WorkflowRuntime("workflowServicesConfig");
    ExternalDataExchangeService 
    externalDataExchangeService = new ExternalDataExchangeService();
    workflowRuntime.AddService(externalDataExchangeService);
    workflowRuntime.StartRuntime();
}

  試想一下,現在我們僅僅是有了ASP.NET MVC路由規則的配置、WF運行時的啟動,如果在應用程序中使用某種DI框架,如微軟的Unity,是不是又避免不了要出現這樣的容器初始化代碼呢?

protected void Application_Start()
{
    // 注冊路由規則
    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
    );

    // 啟動工作流
    WorkflowRuntime workflowRuntime 
     = new WorkflowRuntime("workflowServicesConfig");
    ExternalDataExchangeService externalDataExchangeService 
      = new ExternalDataExchangeService();
    workflowRuntime.AddService(externalDataExchangeService);
    workflowRuntime.StartRuntime();

    // 初始化DI容器
    IContainerContext repositoryContainer 
     = ContainerManager.GetContainer("repositoryContainer");
    repositoryContainer.Initialize();
}

  再看看Application_Start事件中的代碼,有ASP.NET MVC的工作,有WF的工作,也有Unity的工作,不知道將來還會有什么?這些原本互相之間沒有任何聯系的代碼,現在卻同時堆在了一起,當每一部分(或者說每一個框架)變化的時候,都會涉及到Application_Start中代碼的修改,顯然違反了OCP原則。那么有沒有一種機制,讓這些互不相干的模塊之間互相獨立,各自發生變化時不影響對HttpApplication?此時我們就需要對HttpApplication進行擴展,提供一個擴展點,讓其他模塊的程序附加到HttpApplication上面。

  可擴展對象模式

  我們知道WCF提供了非常完美的擴展機制,幾乎在服務執行過程中的每一個環節上都提供有擴展點,如ServiceHostBase、OperationContext、InstanceContext、IContextChannel,這些對象都屬于可擴展對象,它們都通過Extensions屬性獲取用于所有擴展的集合。我們能不能使用這種方式對HttpApplication也進行擴展呢,答案自然是肯定的。查閱一下MSDN就會知道在System.ServiceModel命名空間下面提供了這樣的一組接口: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類庫中任何我們想對其進行擴展的對象,或者是一個自定義的類型,都可以使用可擴展對象模式對其進行擴展。

1
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()