摘要:本文介紹如何通過創(chuàng)建三層結(jié)構(gòu)式 ASP.NET 2.0 應(yīng)用程序來維護(hù) IIS 生產(chǎn)服務(wù)器中的成員身份數(shù)據(jù)庫和角色數(shù)據(jù)庫。
簡介 成員身份編輯器 Microsoft Visual Studio 2005 版本中沒有用于維護(hù) Microsoft IIS 中的成員身份數(shù)據(jù)庫和角色數(shù)據(jù)庫的“現(xiàn)成”解決方案。將開發(fā)環(huán)境中的應(yīng)用程序移至 IIS 生產(chǎn)服務(wù)器時這就會是個問題。Microsoft 提供的實用程序 ASP.NET Web Configuration 只能在非生產(chǎn)的開發(fā)環(huán)境中運(yùn)行。本文及其關(guān)聯(lián)代碼將通過對成員和角色管理實現(xiàn)三層式解決方案,同時使用 Microsoft ASP.NET 標(biāo)準(zhǔn)工具,來解決這個問題。這意味著該實用程序?qū)⒖稍谌魏?ASP.NET 2.0 環(huán)境(包括 IIS)中運(yùn)行。該解決方案十分靈活,可以輕易添加到任何現(xiàn)有的 ASP.NET 2.0 網(wǎng)站項目中。 該解決方案的層定義如下。第一層 ASP.NET 頁面(也稱為表示層)通過對象數(shù)據(jù)源與兩個業(yè)務(wù)對象進(jìn)行連接。這些業(yè)務(wù)對象起中間層作用,是成員和角色的包裝程序。第三層(即后端)由 ASP.NET 提供的成員身份和角色管理器 API 組成。中間層對象可以輕松地加入任何 ASP.NET 2.0 項目,并且?guī)缀鯚o需進(jìn)行任何更改就可以直接使用。 本文深入地介紹了中間層(即數(shù)據(jù)對象及其關(guān)聯(lián) ObjectDataSource)的實現(xiàn)。接著,介紹了如何在使用 Microsoft SQL Server Express 2005(捆綁有 Visual Studio 2005)的 ASP.NET Web 項目中使用這些對象。但是由于 Microsoft 提供的成員身份 API 使用其提供商的技術(shù),因此此處介紹的解決方案與數(shù)據(jù)庫無關(guān)。從 LDAP、SQL Server 或 Oracle 即可輕松獲得成員身份和角色信息。 采用的技術(shù) ObjectDataSource 定義了兩個 ObjectDataSource 實例。一個是有關(guān)成員身份數(shù)據(jù)(用戶名、創(chuàng)建日期、批準(zhǔn)狀態(tài)等)的,另一個是有關(guān)角色(管理員、朋友等)的。這兩個數(shù)據(jù)源均完全填充了所有數(shù)據(jù)訪問方法,即兩者都包含執(zhí)行插入、更新、刪除和選擇的 Member 函數(shù)。兩個 ObjectDataSource 實例都返回 Generic List 類型,這意味著在 GridView 中,列名將自動設(shè)置為 ObjectDataSource 的屬性值名。此外,還實現(xiàn)了自定義排序,以便用戶可以單擊 GridView 中的列標(biāo)題來根據(jù)需要對數(shù)據(jù)進(jìn)行正向或反向排序。 SQL Server Express 2005 和 Web.Config 成員身份數(shù)據(jù)庫和角色數(shù)據(jù)庫的數(shù)據(jù)提供程序源是 SQL Server Express 2005。為實現(xiàn)這一點,需要在 web.config 文件中設(shè)置相應(yīng)的條目。本文稍后將對如何從頭開始設(shè)置新項目進(jìn)行簡要的介紹。web.config 文件中未提及 SQL Server Express 2005 的連接字符串,因為它已在 Microsoft .NET 2.0 Framework 的默認(rèn)部分 Machine.Config 文件中定義。 支持 IIS(5.1 和 6.0) Web 服務(wù)器可以為 5.1 版,也可以為 6.0 版。若要對登錄 Web 應(yīng)用程序的多個用戶進(jìn)行測試,必須使用 IIS。內(nèi)置開發(fā) Web 服務(wù)器不能正確保持各不同登錄用戶的狀態(tài)。內(nèi)置開發(fā) Web 服務(wù)器不能正確保持各不同登錄用戶的狀態(tài)。盡管可以使 Asp.net Web 配置工具與 IIS 一起工作,但尚未完成實現(xiàn)這一目的所必需的附加安全工作。 GridView 控件 GridView 用于顯示成員身份和角色的數(shù)據(jù)。如上文所述,由于使用了 ObjectDataSource 的 Generic 類型,GridView 的列名將自動以 ObjectDataSource 的屬性值命名。如果沒有使用 Generic 類型,則列名恢復(fù)為無意義的默認(rèn)值,必須手動逐個進(jìn)行編輯。 應(yīng)用程序和項目 運(yùn)行此實用程序所需的項目非常簡單,并且是獨立的。項目文件可以下載,包含功能完整的示例。由于用戶和角色沒有直接訪問數(shù)據(jù)庫的權(quán)限,因此所要做的事情就是獲取三個數(shù)據(jù)對象(MembershipDataObject.cs、MembershipUserSortable.cs 和 RoleDataObject.cs,請參見圖 2)。 圖 2:成員身份編輯器項目 SamplePages 文件夾中有幾個其他的示例,演示了前面提及的模塊的用法。圖 1 中顯示的 Membership.aspx 即是其中一例,它可用于選擇、更新、插入及刪除成員和角色,以及為成員分配角色。 使用已有工作成員身份模塊的工作 ASP.NET 2.0 應(yīng)用程序時,無需對這些頁面進(jìn)行已做配置之外的外部配置。可以將這些文件直接復(fù)制到項目中,復(fù)制后即可使用。 如果是第一次在應(yīng)用程序中實現(xiàn)成員身份和角色管理,則創(chuàng)建使用這些對象的解決方案的過程如下, 1. 使用 Visual Studio 2005 創(chuàng)建類型為 ASP.NET 網(wǎng)站的新 Web 項目。 ObjectDataSource 詳細(xì)信息 采用 ObjectDataSource 技術(shù)可以創(chuàng)建作用與 SqlDataSource 非常相似的數(shù)據(jù)源,即它提供允許從永久數(shù)據(jù)存儲區(qū)(例如數(shù)據(jù)庫)中進(jìn)行選擇、更新、插入和刪除記錄(或類似記錄的對象)的界面。本文以下各部分將討論 ObjectDataSource 用于操作成員身份的對象(即類文件)。其在項目中的名稱為 MembershipUserODS.cs。 類 (MembershipUserODS) 由于是通過 Microsoft 成員身份 API 檢索數(shù)據(jù),因此使用 ObjectDataSource 來解決問題。第一步是創(chuàng)建獨立的類,該類對 MembershipUser 進(jìn)行包裝,以便它可以與 ObjectDataSource 關(guān)聯(lián)。下例中介紹了一組需要實現(xiàn)的典型方法,本文以下各部分將介紹如何實現(xiàn)每個成員函數(shù)。本文省略了許多細(xì)節(jié),但本文附帶的源代碼中包含這些細(xì)節(jié)。 [DataObject(true) [DataObjectMethod(DataObjectMethodType.Select, true)] [DataObjectMethod(DataObjectMethodType.Insert, true)] 類聲明 上面顯示的類聲明因具有屬性 [(DataObject(true)],比較特殊。此屬性告訴 Visual Studio 2005 ObjectDataSource 創(chuàng)建向?qū)?,在?shù)據(jù)類中搜索 DataObject 時只查找具有此特殊屬性的成員。請參閱本部分中介紹在何處為 GridView 組件分配此類的示例。 Insert 方法 各部分的細(xì)節(jié)都涉及以非常簡單的方式使用 Microsoft 提供的成員身份 API。例如,下面是一個較詳細(xì)的典型 Insert 方法。 [DataObjectMethod(DataObjectMethodType.Insert,true)] 此類 Insert 是多態(tài)的,這意味著可以存在用于不同目的的多個 Insert 方法。例如,動態(tài)決定是否應(yīng)該根據(jù)環(huán)境批準(zhǔn)創(chuàng)建的用戶時,可能需要使用它。又如,在管理屏幕中創(chuàng)建的新用戶可能想創(chuàng)建默認(rèn)為已批準(zhǔn)的用戶,而用戶注冊屏幕可能默認(rèn)為未批準(zhǔn)。為此,需要另一個具有額外參數(shù)的 Insert 方法??蓪崿F(xiàn)此目標(biāo)的 Insert 方法大致如下。 [DataObjectMethod(DataObjectMethodType.Insert,false)] 與此處所列的其他方法一樣,顯示的示例并非附帶源中實際存在的示例。此處的示例是為了說明各個方法的典型用法。源代碼中包含的用法更為完備且?guī)в凶⑨尅?/p> Update 方法 Update 方法是實現(xiàn)成員身份 API 的一種非常簡單的方法。與 Insert 方法一樣,Update 方法也可以有多種實現(xiàn)。此處只介紹一種實現(xiàn)。在可下載的代碼中,有更多 Update 的多態(tài)實現(xiàn),其中一種只設(shè)置 IsApproved 屬性(如下例所示)。 [DataObjectMethod(DataObjectMethodType.Update,false)] Delete 方法 Delete 方法是最簡單的方法,它只使用一個參數(shù) UserName。 static public void Delete(string UserName) 具有 Sort 屬性的 Select 方法 在本示例中,Select 方法 GetMembers 具有多個組件,每個組件都值得介紹。首先介紹其返回的值,然后是方法本身,最后介紹其如何排序返回值。 Select 方法的返回值(類型為 Collection) Select 方法(也稱為 Get)的返回值為 Generic Collection 類。使用 Generic 是因為最終與該類關(guān)聯(lián)的 ObjectDataSource 使用反射來確定列名和類型。這些名稱和類型與返回的每行數(shù)據(jù)相關(guān)聯(lián)。此方法與 SqlDataSource 使用表或存儲過程的數(shù)據(jù)庫元數(shù)據(jù)來確定每行的列名相同。由于 Select 方法的返回類型為 MembershipUserWrapper(繼承自 MembershipUser),此類的大多數(shù)屬性都是與 MembershipUser 關(guān)聯(lián)的相同屬性。這些屬性包括, • ProviderUserKey 在此插一句,屬性值有一個非常好的特點 - 它們可以是只讀的(無設(shè)置方法)、只寫的(無讀取方法),當(dāng)然也可以是讀/寫的。ObjectDataSource 向?qū)Э紤]到了這一點,并創(chuàng)建了相應(yīng)的參數(shù),這樣在使用 ObjectDataSource 呈現(xiàn)數(shù)據(jù)控件時,只有可更新(讀/寫)的字段能夠編輯。這意味著您不能更改某些屬性,例如 UserName 屬性。如果這一點現(xiàn)在還不清楚,稍后在我們更詳細(xì)地闡述 ObjectDataSource 和數(shù)據(jù)組件時,就容易明白。 Select 方法本身 與 Insert 和 Update 方法一樣,Select 方法也是多態(tài)的。有多少種情況,就可以有多少種 Select 方法。例如,最好能夠使用 Select 方法按照用戶的批準(zhǔn)狀態(tài)(已批準(zhǔn)、未批準(zhǔn)或兩者)來選擇用戶。通常,有一個 Get 方法具有與其關(guān)聯(lián)的盡可能多的參數(shù),其他 Get 方法對其進(jìn)行調(diào)用。在我們的示例中,有三個 Get 方法,一個檢索所有記錄,一個根據(jù)批準(zhǔn)狀態(tài)檢索記錄,一個根據(jù)選擇字符串檢索單個記錄。下例介紹的是調(diào)用返回所有用戶的方法。將兩個布爾值均設(shè)置為 true,可以返回所有用戶。 [DataObjectMethod(DataObjectMethodType.Select, true)] 下面的示例介紹了一個較詳細(xì)的 Get 方法。此示例僅介紹方法的開頭部分,未介紹方法的詳細(xì)信息,包括完成屬性分配、按批準(zhǔn)狀態(tài)篩選并拒絕不滿足條件的記錄,以及應(yīng)用排序條件。此示例后面是有關(guān)排序條件的詳細(xì)說明。(請注意,對包含數(shù)百個用戶 [不超過五百] 的數(shù)據(jù)庫調(diào)用 GetAllUsers,很快就會成為代價非常高昂的操作。) [DataObjectMethod(DataObjectMethodType.Select, true)] 自定義排序條件 請注意,在前面的代碼中,名為 sortData 的參數(shù)字符串傳遞到了 GetMembers 中。如果在 ObjectDataSource 聲明中,SortParameterName 被指定為其一個屬性,則此參數(shù)將自動傳遞到所有 Select 方法。其值將為數(shù)據(jù)控件列中的 SortExpression 屬性指定的名稱。在我們的示例中,數(shù)據(jù)控件為 GridView。 Comparer 方法是根據(jù)傳遞給 GetMembers 方法的 sortName 參數(shù)調(diào)用的。由于這些 ASP.NET 網(wǎng)頁無狀態(tài),因此必須假定當(dāng)前排序的方向(正向或反向)存儲在視圖狀態(tài)中。每次調(diào)用都顛倒前一次調(diào)用的方向。即用戶單擊列標(biāo)題時,在正向排序和反向排序之間切換。 假定使用的是 GridView,傳遞到 GetMembers(sortData) 的參數(shù)中包含 GridView 列的屬性 SortExpression 中的數(shù)據(jù)。如果請求反向排序,則“DESC”一詞附加在排序字符串后面。例如,用戶第一次單擊 Email 列時,傳遞到 GetMembers 的 sortData 為“Email”。用戶第二次單擊該列時,參數(shù) sortData 就變?yōu)?#8220;Email DESC”,然后是“Email”、“Email DESC”,依此類推。特別需要注意的是,第一次加載頁面時,傳遞的 sortData 參數(shù)是零長度的字符串(非空)。下面是 GetMembers 方法的一部分,該方法檢索數(shù)據(jù)并對其進(jìn)行排序,以便按正確的順序返回這些數(shù)據(jù)。 [DataObjectMethod(DataObjectMethodType.Select, true)] foreach (MembershipUser mu in muc) ... Code that implements Comparison memberList.Sort(comparison); 在下一部分中,將此并入 GridView 中后,就比較清楚了。 ObjectDataSource 聲明 聲明 ObjectDataSource 最簡單的方法是,先使用 Visual Studio 2005 向?qū)?chuàng)建一個空的 ASP.NET 頁面,然后將數(shù)據(jù)控件中的數(shù)據(jù)控件拖放到工具欄中。創(chuàng)建 ObjectDataSource 后,可以獲取新建 ObjectDataSource 右上角的小標(biāo)記;然后單擊 Configure Data Source(配置數(shù)據(jù)源)打開一個向?qū)В渲酗@示“Configure Data Source-ObjectDataSource1”(配置數(shù)據(jù)源 - ObjectDataSource1)(請參見圖 3)。 圖 3:配置 ObjectDataSource 此時,將顯示可與 ObjectDataSource 關(guān)聯(lián)的兩個類。MembershipUserODS 是本文的主要主題。RoleDataObject 基本相同,但其封裝成員身份角色。另外,請記住,此處顯示的只是聲明具有特殊類屬性 [DataObject(true)](在“類定義”中介紹)的對象。 選擇 MembershipUserODS 后,將顯示一個具有四個選項卡的對話框。要通過 MembershipUserODS 類調(diào)用的方法將在這些選項卡中定義。Select、Update、Insert 和 Delete 方法將與 MembershipUserODS 中的成員函數(shù)關(guān)聯(lián)。在許多情況下,類中都有多種方法適用于其中每種情況。必須根據(jù)所需數(shù)據(jù)方案選擇一個適當(dāng)?shù)姆椒?。圖 4 中顯示了這四個選項卡。默認(rèn)情況下,將在這些選項卡中填充標(biāo)有特殊屬性 [DataObjectMethod(DataObjectMethodType.Select, false)] 的成員。當(dāng)然,此特殊屬性是 Select 的默認(rèn)值。將表達(dá)式 DataObjectMethodType.Select 改為 DataObjectMethodType.Insert、DataObjectMethodType.Update 和 DataObjectMethodType.Delete 將為其他選項卡確定相應(yīng)的默認(rèn)值。第二個參數(shù)是一個布爾值,表示此方法(請記住,它能以多態(tài)方式定義)是默認(rèn)方法,應(yīng)在選項卡控件中使用。 Select 方法 如前面在介紹 MembershipUserODS 類的部分中所述,GetMembers 函數(shù)返回 Generic Collection 類。這樣,此處定義的 ObjectDataSourceMembershipUser 控件可以使用反射,并確定與 GetMembers 調(diào)用關(guān)聯(lián)的調(diào)用參數(shù)。在本示例中,用于調(diào)用 GetMembers 的參數(shù)是 returnAllApprovedUsers、returnAllNotApprovedUsers、userNameToFind 和 sortData。基于此,新 ObjectDataSource 的實際定義如下。 圖 4:指定 Select 方法 <asp:ObjectDataSource ID="ObjectDataSourceMembershipUser"runat="server" Insert 方法 在本示例中,Insert 方法被指定給成員函數(shù) Insert()。請注意,調(diào)用此方法時只使用了兩個參數(shù),UserName 和 Password(請參見圖 5)。參數(shù)的數(shù)目必須等于 ObjectDataSource 中聲明的參數(shù)的數(shù)目。ObjectDataSource 中的參數(shù)聲明如下所示。另一個定義的函數(shù)為 Insert Member,用于添加第三個參數(shù),approvalStatus。如果此 ObjectDataSource 的功能要包括在設(shè)置 approvalStatus 時進(jìn)行插入操作,則應(yīng)從下拉列表中選擇其他 Insert 方法。這會導(dǎo)致以下 InsertParameters 插入 .aspx 頁面中。如果選擇包含兩個參數(shù)的方法,則塊中不會包括名為 isApproved 的 asp:Parameter。請記住,本示例可能與附帶的源代碼不一致,此處僅作為示例。附帶的源代碼要完整得多。 圖 5:指定 Insert 方法 <asp:ObjectDataSource ID="ObjectDataSourceMembershipUser"runat="server" 請記住,如果使用的是具有最少參數(shù)的 Insert 方法,則需要在方法中設(shè)置默認(rèn)密碼。在生產(chǎn)系統(tǒng)中,這是個糟糕的辦法。有關(guān)如何處理插入的更好示例,請參閱附帶的源代碼。具體地說,請參閱 Membership.aspx 頁面了解此功能。 Update 方法 在本示例中,Update 方法被指定給成員函數(shù) Update()。請注意,調(diào)用此方法時使用了多個參數(shù),UserName、Email、isApproved 和 Comment(請參見圖 6)。此外,還有一種 Update 方法,它包含所有可更新參數(shù)。如果要創(chuàng)建具有盡可能多的更新功能的控件,這很有用。與 Insert 一樣,為此 ObjectDataSource 選擇適當(dāng)?shù)?Update 方法。完成向?qū)Ш?,將自動?chuàng)建 UpdateParameters,如下所示。 圖 6:指定 Update 方法 <asp:ObjectDataSource ID="ObjectDataSourceMembershipUser"runat="server" Delete 方法 在本示例中,Delete 方法被指定給成員函數(shù) Delete()。當(dāng)然,只需一個 Delete 方法(請參見圖 7)。下面是支持此 Delete 方法的 ObjectDataSource 的聲明。 圖 7:指定 Delete 方法 <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 類 (RoleDataObject) 與成員身份一樣,設(shè)置角色時也使用其自己的 DataObject。由于角色無特殊之處,本文不對其設(shè)置進(jìn)行詳細(xì)介紹。了解成員身份 DataObject 的設(shè)置方式后,即可了解角色的設(shè)置方式。在成員身份中,封裝成員身份 API 的 Microsoft C# 對象是 MembershipDataObject.cs。封裝角色 API 的相似類是 RoleDataObject.cs。 GridView 中的 ObjectDataSource(數(shù)據(jù)控件) 本文的前面部分中已建立了成員身份用戶和角色的類聲明。此外,還在 ASP.NET 頁面中加入了完整的 ObjectDataSource 對象。最后一步是創(chuàng)建用戶界面,也稱為應(yīng)用程序的用戶互動層或表示層。由于創(chuàng)建的對象完成了這么多的工作,因此所需做的只是創(chuàng)建簡單的 GridView 并將其與 ObjectDataSource 關(guān)聯(lián)。步驟如下, 1. 在 ASP.NET 頁面設(shè)計器的可視模式下,將 GridView 數(shù)據(jù)組件拖放到先前創(chuàng)建的 ObjectDataSource 關(guān)聯(lián)頁面中。 圖 8 顯示的是與配置 Gridview 關(guān)聯(lián)的對話框。 圖 8:配置 GridView 此處應(yīng)特別注意,下面顯示的 GridView 控件中的 DataKeyNames 是自動設(shè)置的。這是因為,在具有屬性 [DataObjectField(true)] 的 MembershipUserSortable 類中對主鍵添加了標(biāo)記,如下所示。請注意,由于 UserName 是 MembershipUser 類的屬性,需要在擴(kuò)展 MembershipUser 的類中提供默認(rèn)屬性。由于是只讀屬性,因此只聲明了 Get 方法(對于 MembershipUser,UserName 是公共虛擬的)。 [DataObjectField(true)] GridView 中有一個屬性必須手動設(shè)置,必須在控件中設(shè)置主鍵。為此,需要將屬性 DataKeyName 與 UserName 相關(guān)聯(lián)。GridView 聲明如下。 <asp:GridView ID="GridView1" DataKeyNames="UserName" runat="server" 結(jié)論 至此,您現(xiàn)在應(yīng)熟悉如何創(chuàng)建自己的三層結(jié)構(gòu)式 ASP.NET 應(yīng)用程序。此外,目前還要有兩個可任意使用來封裝成員和角色的對象。例如,現(xiàn)在可以使用 DetailView 控件,在幾分鐘內(nèi)創(chuàng)建一個針對成員的完整 DetailView 界面,用于對成員進(jìn)行導(dǎo)航、插入、更新及刪除操作。試一試吧! 我并未具體介紹如何實現(xiàn)添加、更新和刪除成員或角色。如果您查看源代碼,就會發(fā)現(xiàn)我使用 API 的方法非常簡單。在此詳細(xì)介紹那些調(diào)用并無多大用處,因為我確信,如果您仍在閱讀本文,您會和我一樣,邊學(xué)邊實踐。 今年我有幸參加了在奧蘭多舉辦的 MS TechEd 和在洛杉磯舉辦的 PDC,有機(jī)會向 ASP.NET 小組請教了許多問題。特別感謝 Brad Millington 和 Stefan Schackow 在這幾周解答了我提出的許多問題,感謝 Jeff King 和 Brian Goldfarb 對本文進(jìn)行潤色提供的所有幫助。從某些方面來講,本文是對提供過幫助的人的回報,希望他們將來不必回答這么多問題。 作者:Peter Kellner 來源:MSDN (責(zé)任編輯:webjx)
|
|