接口: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 } }
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]瞭解。