深入ASP.NET 2.0的提供者模型(1)
一、引言
早在2001年,我就著手開發一個ASP.NET在線消息板應用程序WebForums.NET。其目的是創建一個基于ASP.NET的消息板系統,而且該系統可以容易插入到一個現有網站中。構建這樣一個端對端應用程序的特別挑戰之一就是,要為客戶提供一種方式以便能夠把它集成到他們自己的系統中去。例如,一個在線論壇明顯需要使用某種數據存儲來存儲用戶信息、論壇、回寄信息等;但是,最好不要把客戶鎖定到一種特定的數據存儲中。也就是說,你不應該說,“我的應用程序必須使用微軟的SQLServer2000”;因為這樣的話,使用Oracle或Access的客戶怎么會使用你的軟件呢?
另一個集成到客戶現有數據中的問題是,所有的在線論壇站點都提供用戶帳戶和一種創建新帳戶的方式。典型情況下,這被建模為一個論壇架構(以一個數據庫中的Users表形式存在)。但是,客戶很可能已經有他們自己的擁有成千的用戶帳戶的數據庫表。或者,一個客戶可能想在一個內部網設置中使用該論壇,并且想使用活動目錄而不是某種數據庫表來認證和存儲用戶信息。因此,當一個論壇軟件系統創建一個Users數據庫表并對其客戶說"這就是你存儲用戶的方式"時,那些已經擁有現有基礎結構和用戶數據的客戶很可能會疏遠這樣的軟件。
因此,當你使用一種“僵硬”的API構建一個系統時,會產生特別的挑戰。一種“僵硬”的API不是提供一種方式來定制邏輯而是硬編碼實現細節(例如,你必須使用SQLServer作為你的后端數據存儲,且在這個數據庫有一個Users表,并將在其中存儲所有的用戶信息)。然而,通過使用提供者設計模式,你可以輕易地打破這種"僵硬"性。借助于提供者設計模式,系統架構師只需要定義API,至于編程功能則由系統來提供。對于一個在線論壇應用程序來說,這可能包括一個具有例如Authenticate(username,password)和GetUserDetails(username)等方法的Users類。
提供者模型的優秀在于客戶實現方案可以指定一個系統應該使用的定制類。這種定制類必須實現系統的良好定義的API;但是,它允許無縫地插入任何定制實現。也就是說,一旦定義這個API,系統實現者可以創建一個使用SQLServer和一個Users表的默認的具體實現-大多數客戶可以直接使用之而不必要作任何修改。那些有定制需要的客戶(他們想使用Oracle或以另外一些方式存儲用戶數據)可以創建他們自己的類,該類提供必要的功能并且把它們插入到這些客戶的系統中。
其實,提供者設計模式被應用于整個ASP.NET2.0實現中。當然,網上也存在一些如何在ASP.NET1.x應用程序中使用這一功能的教程。
在本文中,我們將詳細探討提供者模型并分析如何把它應用于ASP.NET2.0開發中。
二、打破“僵硬”的API實現
在我早期的WebForums.NET開發中,我認識到,這種"僵硬"的API實現將會成為一個問題。我的軟件設計目標之一就是:盡可能靈活且可定制,并且使用戶使用SQLServer,而且我的用戶數據模型實現應該看起來充其量只是有些限制性。為了克服這些問題,我構建了一個包含下面兩部分的系統:
1.一組定義了系統的核心功能的抽象基類;
2.能夠在運行時刻動態地加載一個擴展抽象基類。該代碼負責檢查包含一個<ConfigSetting>節(該節中給出要使用的類的完全限定名)的Web.config文件。
借助于這一架構,我可以通過一系列抽象基類來定義系統的功能,并使用SQLServer2000和Users表來提供這些類的具體實現。滿足這一配置的客戶可以只管使用該應用程序,并且一切將工作良好,且不需要他們編寫一行代碼。然而,那些需要定制的開發者們可以通過創建他們自己的派生自適當的抽象基類的類來實現。通過簡單地把該程序集放到應用程序的/bin目錄并更新Web.config文件,他們可以讓系統使用這個新類。具體地說,WebForums.NET發行中帶有一個抽象基類DataProvider,它清楚地列舉出了系統中的所有方法,類似如下:
publicabstractclassDataProvider { publicabstractboolAuthenticateUser(stringusername,stringpassword); publicabstractUserGetUserInfo(stringusername); ... publicstaticDataProviderInstance() { ... } }
AuthenticateUser(username,password)和GetUserInfo(username)方法是系統定義的許多方法中的兩個方法的代表。而靜態Instance()方法是該DataProvider類的主要實現;而DataProvider類包含檢查代表了WebForums.NET配置信息(該信息指示系統要使用的類的全稱限定名)的Web.config文件的代碼。然后,該方法使用反射(和緩沖)來創建該類的一個實例并且把它返回到系統。
WebForums.NET發行中還帶有一個派生自DataProvider基類的SqlDataProvider類,這個類提供分類方法的具體實現。例如,SqlDataProvider的所有方法都可以操作存儲于一個SQLServer2000數據庫中的數據;與用戶相關的方法可以與一個預定義的Users數據庫表一起工作。一個想改變后端功能的客戶可以創建他自己的派生自DataProvider的類,這些信息都可以展示于Web.config文件中(指明應該使用他們的定制類)。例如,WebForums.NET中的Web.config可能包括下列內容:
<WebForumsSettings> <addkey="DataProviderAssemblyPath"value="path"/> <addkey="DataProviderClassName"value="Namespace.Classname"/> </WebForumsSettings>
默認情況下,這個設置信息引用隨同WebForums.NET一起發行的SqlDataProvider類。然而,如果一個客戶創建他自己的API實現,那么他可以提供自己的類的細節,并且系統會自動地開始使用他的實現來創建默認實現。
借助于這一架構,使用WebForums.NET的頁面開發者可以使用如下所示的代碼來認證一個用戶:
if(DataProvider.Instance().AuthenticateUser(username,password)) //用戶被認證 else //用戶名/口令無效!
當調用DataProvider.Instance()方法時,上面的配置文件被檢查并且返回適當類的一個實例。如果客戶還沒有創建他們自己的實現的話,這將是默認的SqlDataProvider類;而如果他們已經實現的話,它將是他們自己的類。一旦DataProvider.Instance()方法返回一個適當的提供者實例,我們就可以簡單地調用該API的成員(在這個例子中是AuthenticateUser())。
留言列表