|
概述
HttpApplication對(duì)象對(duì)于做ASP.NET開(kāi)發(fā)的朋友,我想沒(méi)有人不熟悉它。在ASP.NET開(kāi)發(fā)中,經(jīng)常避免不了要在HttpApplication中執(zhí)行一些操作,如使用了ASP.NET MVC框架,就會(huì)在Application_Start 事件中避免不了這樣的路由規(guī)則配置代碼:
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
);
}
如果僅僅是這一條,看起來(lái)倒不覺(jué)的有什么問(wèn)題,但如果同時(shí)在應(yīng)用程序中使用了工作流,又避免不了在Application_Start出現(xiàn)啟動(dòng)工作流運(yùn)行時(shí)的代碼:
protected void Application_Start()
{
// 注冊(cè)路由規(guī)則
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
);
// 啟動(dòng)工作流
WorkflowRuntime workflowRuntime = new WorkflowRuntime("workflowServicesConfig");
ExternalDataExchangeService
externalDataExchangeService = new ExternalDataExchangeService();
workflowRuntime.AddService(externalDataExchangeService);
workflowRuntime.StartRuntime();
}
試想一下,現(xiàn)在我們僅僅是有了ASP.NET MVC路由規(guī)則的配置、WF運(yùn)行時(shí)的啟動(dòng),如果在應(yīng)用程序中使用某種DI框架,如微軟的Unity,是不是又避免不了要出現(xiàn)這樣的容器初始化代碼呢?
protected void Application_Start()
{
// 注冊(cè)路由規(guī)則
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
);
// 啟動(dòng)工作流
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的工作,不知道將來(lái)還會(huì)有什么?這些原本互相之間沒(méi)有任何聯(lián)系的代碼,現(xiàn)在卻同時(shí)堆在了一起,當(dāng)每一部分(或者說(shuō)每一個(gè)框架)變化的時(shí)候,都會(huì)涉及到Application_Start中代碼的修改,顯然違反了OCP原則。那么有沒(méi)有一種機(jī)制,讓這些互不相干的模塊之間互相獨(dú)立,各自發(fā)生變化時(shí)不影響對(duì)HttpApplication?此時(shí)我們就需要對(duì)HttpApplication進(jìn)行擴(kuò)展,提供一個(gè)擴(kuò)展點(diǎn),讓其他模塊的程序附加到HttpApplication上面。
可擴(kuò)展對(duì)象模式
我們知道WCF提供了非常完美的擴(kuò)展機(jī)制,幾乎在服務(wù)執(zhí)行過(guò)程中的每一個(gè)環(huán)節(jié)上都提供有擴(kuò)展點(diǎn),如ServiceHostBase、OperationContext、InstanceContext、IContextChannel,這些對(duì)象都屬于可擴(kuò)展對(duì)象,它們都通過(guò)Extensions屬性獲取用于所有擴(kuò)展的集合。我們能不能使用這種方式對(duì)HttpApplication也進(jìn)行擴(kuò)展呢,答案自然是肯定的。查閱一下MSDN就會(huì)知道在System.ServiceModel命名空間下面提供了這樣的一組接口:IExtensibleObject、IExtension和IExtensionCollection,這是可擴(kuò)展對(duì)象模式中最重要的三個(gè)接口,也只有這三個(gè)接口。
IExtensibleObject自然是定義了可擴(kuò)展對(duì)象,即我們要對(duì)誰(shuí)進(jìn)行擴(kuò)展,它的定義非常簡(jiǎn)單,僅僅是提供了一個(gè)只讀的屬性Extensions,用來(lái)提供所有擴(kuò)展對(duì)象的集合,如下代碼所示:
public interface IExtensibleObject<T> where T : IExtensibleObject<T>
{
IExtensionCollection<T> Extensions { get; }
}
IExtension定義了擴(kuò)展對(duì)象的契約,使對(duì)象可以通過(guò)聚合擴(kuò)展另一個(gè)對(duì)象(此處的另一個(gè)對(duì)象,就是指上面所講的擴(kuò)展宿主IExtensibleObject),在IExtension中定義了兩個(gè)非常重要的方法Attach和Detach方法,分別用來(lái)提供聚合或解聚的通知。
public interface IExtension<T> where T : IExtensibleObject<T>
{
void Attach(T owner);
void Detach(T owner);
}
當(dāng)一個(gè)擴(kuò)展對(duì)象IExtension附加到可擴(kuò)展對(duì)象的擴(kuò)展集合中時(shí),它的Attach方法將會(huì)被調(diào)用;反之如果從集合中移除一個(gè)擴(kuò)展對(duì)象時(shí),它的Detach方法會(huì)被調(diào)用。這一點(diǎn)我們可以通過(guò)Reflector來(lái)得到驗(yàn)證,如下代碼所示:
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);
}
}
最后一個(gè)接口是IExtensionCollection,它是IExtension對(duì)象的集合。
對(duì)HttpApplication進(jìn)行擴(kuò)展
下面我們就看一下如何使用可擴(kuò)展對(duì)象模式對(duì)HttpApplication進(jìn)行擴(kuò)展,首先定義可擴(kuò)展對(duì)象,讓ExtensibleHttpApplication派生于HttpApplication,并實(shí)現(xiàn)了IExtensibleObject接口,泛型的參數(shù)類型就是它自身,如下代碼所示:
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;
}
}
}
有了可擴(kuò)展的HttpApplication之后,需要在HttpApplication中實(shí)現(xiàn)任何功能,都可以作為一個(gè)擴(kuò)展附加到ExtensibleHttpApplication上去,如實(shí)現(xiàn)ASP.NET MVC路由,可以定義一個(gè)如下代碼所示的擴(kuò)展對(duì)象:
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中啟動(dòng)Workflow,可以再針對(duì)Workflow定義一個(gè)擴(kuò)展對(duì)象,如下示例代碼所示:
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();
}
}
我們已經(jīng)定義好了相應(yīng)的擴(kuò)展對(duì)象,只需要在相應(yīng)的HttpApplication把擴(kuò)展對(duì)象附加到ExtensibleHttpApplication上即可,修改Global.asax中的代碼如下所示:
public class MvcApplication : ExtensibleHttpApplication
{
protected void Application_Start()
{
this.Extensions.Add(new MvcHttpApplication());
this.Extensions.Add(new WorkflowHttpApplication());
}
}
現(xiàn)在代碼是不是看起來(lái)優(yōu)雅多了?現(xiàn)在如果要在Application_Start中,添加另外一些執(zhí)行代碼,只需要編寫(xiě)相應(yīng)的擴(kuò)展對(duì)象,并將其添加到Extension集合中即可。也許有朋友會(huì)問(wèn),這樣每添加一些新的代碼,還是要修改Application_Start中的代碼啊?別忘了,可以通過(guò)配置可以解決這個(gè)問(wèn)題,WCF中的擴(kuò)展不也是可以采用配置方式實(shí)現(xiàn),不是嗎?同樣,如果我們需要在Application_End事件中釋放某些對(duì)象,可以直接從擴(kuò)展集合中移除它,此時(shí)將會(huì)調(diào)用它的Detach方法。
總結(jié)
本文介紹了如何使用WCF中提供的可擴(kuò)展對(duì)象模式擴(kuò)展HttpApplication,事實(shí)上可擴(kuò)展對(duì)象模式的作用遠(yuǎn)不在此,它可以擴(kuò)展.NET類庫(kù)中任何我們想對(duì)其進(jìn)行擴(kuò)展的對(duì)象,或者是一個(gè)自定義的類型,都可以使用可擴(kuò)展對(duì)象模式對(duì)其進(jìn)行擴(kuò)展。
NET技術(shù):技巧:使用可擴(kuò)展對(duì)象模式擴(kuò)展HttpApplication,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。