儲存其他的使用者資訊 (C#)
注意
自本文撰寫以來,ASP.NET 成員資格提供者已被 ASP.NET 身分識別取代。 強烈建議您更新應用程式以使用 ASP.NET 身分識別 平臺,而不是本文撰寫時精選的成員資格提供者。 ASP.NET 身分識別對於 ASP.NET 成員資格系統有一些優點,包括 :
- 更好的效能
- 改善擴充性和可測試性
- 支援 OAuth、OpenID Connect 和雙因素驗證
- 宣告型身分識別支援
- 與 ASP.Net Core 更好的互通性
在本教學課程中,我們將藉由建置非常基本的客體簿應用程式來回答這個問題。 如此一來,我們將探討資料庫中用來建立使用者資訊模型化的不同選項,然後瞭解如何將此資料與成員資格架構所建立的使用者帳戶產生關聯。
簡介
Asp。NET 的成員資格架構提供彈性的介面來管理使用者。 成員資格 API 包含驗證認證的方法、擷取目前登入使用者的相關資訊、建立新的使用者帳戶,以及刪除使用者帳戶等等。 成員資格架構中的每個使用者帳戶只包含驗證認證和執行基本使用者帳戶相關工作所需的屬性。 這是由 類別的方法和屬性MembershipUser
所辨識,其會建立成員資格架構中使用者帳戶的模型。 這個類別具有 、、 和 IsLockedOut
等屬性 UserName
,以及 和 等 UnlockUser
GetPassword
方法。 Email
通常,應用程式需要儲存成員資格架構中未包含的其他使用者資訊。 例如,線上零售商可能需要讓每位使用者儲存出貨和帳單位址、付款資訊、遞送喜好設定,以及連絡人電話號碼。 此外,系統中的每個訂單都會與特定的使用者帳戶相關聯。
類別 MembershipUser
不包含 或 DeliveryPreferences
PastOrders
之類的 PhoneNumber
屬性。 那麼,如何追蹤應用程式所需的使用者資訊,並將其與成員資格架構整合? 在本教學課程中,我們將藉由建置非常基本的客體簿應用程式來回答這個問題。 如此一來,我們將探討資料庫中用來建立使用者資訊模型化的不同選項,然後瞭解如何將此資料與成員資格架構所建立的使用者帳戶產生關聯。 現在就開始吧!
步驟 1:建立客體簿應用程式的資料模型
有各種不同的技術可用來擷取資料庫中的使用者資訊,並將它與成員資格架構所建立的使用者帳戶產生關聯。 為了說明這些技術,我們必須增強教學課程 Web 應用程式,以便擷取某種使用者相關資料。 (目前,應用程式的資料模型只包含 .) 所需的 SqlMembershipProvider
應用程式服務資料表
讓我們建立非常簡單的客體簿應用程式,讓已驗證的使用者可以留下批註。 除了儲存來賓簿批註之外,讓我們允許每位使用者儲存他的住家城市、首頁和簽章。 如果提供,使用者的住家城市、首頁和簽章會出現在來賓簿中離開的每個訊息上。
GuestbookComments
新增資料表
為了擷取客體簿批註,我們需要建立名為 GuestbookComments
的資料庫資料表,其具有 、 Subject
、 Body
和 CommentDate
等 CommentId
資料行。 我們也需要讓資料表中的每個 GuestbookComments
記錄參考離開批註的使用者。
若要將此資料表新增至資料庫,請移至 Visual Studio 中的 [資料庫總管],然後向下切入至 SecurityTutorials
資料庫。 以滑鼠右鍵按一下 [資料表] 資料夾,然後選擇 [新增資料表]。 這會顯示一個介面,可讓我們定義新資料表的資料行。
圖 1:將新的資料表新增至 SecurityTutorials
資料庫 (按一下即可檢視完整大小的影像)
接下來,定義 GuestbookComments
的資料行。 首先,新增名為 CommentId
類型的 uniqueidentifier
資料行。 此資料行會唯一識別客體簿中的每個批註,因此不允許 NULL
,並將它標示為數據表的主鍵。 我們可以藉由將資料行的預設值設定為 INSERT
CommentId
,來指出應該針對這個欄位自動產生新的 uniqueidentifier
值,而不是為每個 欄位 INSERT
提供值 NEWID()
。 新增此第一個欄位,並將其標示為主鍵,並設定其預設值之後,您的畫面看起來應該類似圖 2 所示的螢幕擷取畫面。
圖 2:新增名為 CommentId
(按一下即可檢視完整大小的影像)
接下來,新增名為 Subject
類型的 nvarchar(50)
資料行和類型 nvarchar(MAX)
為 Body
的資料行,不允許 NULL
在這兩個數據行中使用 。 接著,新增名為 CommentDate
類型的 datetime
資料行。 不允許 NULL
,並將資料 CommentDate
行的預設值設定為 getdate()
。
所有保留專案都是新增一個資料行,以將使用者帳戶與每個客體簿批註產生關聯。 其中一個選項是新增類型 nvarchar(256)
為 的資料 UserName
行。 使用 以外的 SqlMembershipProvider
成員資格提供者時,這是適當的選擇。 但是,使用 SqlMembershipProvider
時,如同我們在本教學課程系列中, UserName
資料表中的資料 aspnet_Users
行不保證是唯一的。 資料表 aspnet_Users
的主鍵為 UserId
,且 類型 uniqueidentifier
為 。 因此, GuestbookComments
資料表需要名為 UserId
的資料行, uniqueidentifier
(不允許 NULL
值) 。 繼續並新增此資料行。
注意
如我們在SQL Server教學課程中建立成員資格架構中所述,成員資格架構的設計目的是讓具有不同使用者帳戶的多個 Web 應用程式共用相同的使用者存放區。 其作法是將使用者帳戶分割成不同的應用程式。 而且,雖然每個使用者名稱保證在應用程式中都是唯一的,但相同的使用者名稱可能會用於使用相同使用者存放區的不同應用程式中。 和 ApplicationId
欄位上的 aspnet_Users
資料表 UserName
中有複合 UNIQUE
條件約束,但不只是欄位上的 UserName
條件約束。 因此,aspnet_Users資料表可能會有兩個具有相同值的 (或更多) 記錄 UserName
。 不過,資料表欄位 UserId
(有一個 UNIQUE
條件約束 aspnet_Users
,因為它是主鍵) 。 UNIQUE
條件約束很重要,因為若沒有條件約束,就無法在 和 aspnet_Users
資料表之間建立 GuestbookComments
外鍵條件約束。
新增資料 UserId
行之後,按一下工具列中的 [儲存] 圖示來儲存資料表。 將新資料表 GuestbookComments
命名為 。
我們最後有一個問題要與資料表一起處理 GuestbookComments
:我們需要在資料行與 aspnet_Users.UserId
資料行之間建立 GuestbookComments.UserId
外鍵條件約束。 若要達到此目的,請按一下工具列中的 [關聯性] 圖示,以啟動 [外鍵關聯性] 對話方塊。 (或者,您可以移至 [資料表Designer] 功能表並選擇 [關聯性.) ] 來啟動此對話方塊
按一下 [外鍵關聯性] 對話方塊左下角的 [新增] 按鈕。 這將會新增外鍵條件約束,雖然我們仍然需要定義參與關聯性的資料表。
圖 3:使用 [外鍵關聯性] 對話方塊來管理資料表的外鍵條件約束, (按一下即可檢視大小完整的影像)
接下來,按一下右側 [資料表和資料行規格] 資料列中的省略號圖示。 這會啟動 [資料表和資料行] 對話方塊,我們可以從中指定主鍵資料表和資料行,以及資料表中的 GuestbookComments
外鍵資料行。 特別是,請選取 aspnet_Users
並 UserId
做為主鍵資料表和資料行,並從 UserId
GuestbookComments
資料表選取做為外鍵資料行, (請參閱圖 4) 。 定義主鍵和外鍵資料表和資料行之後,按一下 [確定] 返回 [外鍵關聯性] 對話方塊。
圖 4:在 和 GuesbookComments
資料表之間建立 aspnet_Users
外鍵條件約束 (按一下即可檢視完整大小的影像)
此時已建立外鍵條件約束。 此條件約束的存在可確保這兩個數據表之間的 關係完整性 ,方法是保證永遠不會有參考不存在使用者帳戶的客體簿專案。 根據預設,如果有對應的子記錄,外鍵條件約束將不允許刪除父記錄。 也就是說,如果使用者提出一或多個來賓簿批註,然後嘗試刪除該使用者帳戶,除非先刪除其來賓簿批註,否則刪除將會失敗。
外鍵條件約束可以設定為在刪除父記錄時自動刪除相關聯的子記錄。 換句話說,我們可以設定此外鍵條件約束,以便在刪除使用者的使用者帳戶時自動刪除使用者的來賓簿專案。 若要達成此目的,請展開 [INSERT 和 UPDATE 規格] 區段,並將 [刪除規則] 屬性設定為 Cascade。
圖 5:將外鍵條件約束設定為串聯刪除 (按一下即可檢視完整大小的影像)
若要儲存外鍵條件約束,請按一下 [關閉] 按鈕以結束外鍵關聯性。 然後按一下工具列中的 [儲存] 圖示,以儲存資料表和此關聯性。
儲存使用者的住家城市、首頁和簽章
下表 GuestbookComments
說明如何儲存與使用者帳戶共用一對多關聯性的資訊。 由於每個使用者帳戶可能有任意數目的相關聯批註,因此建立資料表來保存一組批註,其中包含一個資料行,可將每個批註連結回特定使用者的資料行,來建立此關聯性模型。 使用 SqlMembershipProvider
時,最好建立名為 UserId
類型的 uniqueidentifier
資料行,以及此資料行與 aspnet_Users.UserId
之間的外鍵條件約束來建立此連結。
我們現在需要建立三個數據行與每個使用者帳戶的關聯,以儲存使用者的主市、首頁和簽章,其會出現在來賓簿批註中。 有幾種不同的方式可以完成這項作業:
將新資料行新增至
aspnet_Users
或aspnet_Membership
表。我不建議使用此方法,因為它會修改 所使用的SqlMembershipProvider
架構。 此決策可能會回到您的下路。 例如,如果未來的版本 ASP.NET 使用不同的SqlMembershipProvider
架構,該怎麼辦。 Microsoft 可能包含將 ASP.NET 2.0SqlMembershipProvider
資料移轉至新架構的工具,但如果您已修改 ASP.NET 2.0SqlMembershipProvider
架構,則可能無法進行這類轉換。使用 ASP。NET 的設定檔架構,定義主市、首頁和簽章的配置檔案屬性。 ASP.NET 包含設定檔架構,其設計目的是要儲存額外的使用者特定資料。 如同成員資格架構,設定檔架構是建置在提供者模型之上。 .NET Framework隨附
SqlProfileProvider
sththat 會將設定檔資料儲存在SQL Server資料庫中。 事實上,我們的資料庫已經有 (aspnet_Profile
) 所使用的SqlProfileProvider
資料表,因為我們在 SQL Server 教學課程中 將應用程式服務新增回建立成員資格架構時新增。
設定檔架構的主要優點是,它可讓開發人員定義 中的Web.config
配置檔案屬性,而不需要撰寫程式碼,即可將設定檔資料序列化至基礎資料存放區或從基礎資料存放區序列化。 簡單地說,定義一組配置檔案屬性,並在程式碼中使用它們非常容易。 不過,配置檔案系統在進行版本設定時會留下許多所需專案,因此,如果您有預期稍後要新增新使用者特定屬性的應用程式,或移除或修改現有的屬性,則 Profile 架構可能不是最佳選項。 此外,會SqlProfileProvider
以高度反正規化的方式儲存配置檔案屬性,使得不可能直接對設定檔資料執行查詢 (,例如,有多少使用者擁有紐約) 的家市。
如需設定檔架構的詳細資訊,請參閱本教學課程結尾的一節。將這三個數據行新增至資料庫中的新資料表,並建立此資料表與此資料表之間的一對一關聯性
aspnet_Users
.這種方法牽涉到比使用 Profile 架構還要多一些,但提供在資料庫中如何建立其他使用者屬性模型的最大彈性。 這是我們將在本教學課程中使用的選項。
我們將建立名為 UserProfiles
的新資料表,以儲存每個使用者的住家城市、首頁和簽章。 以滑鼠右鍵按一下 [資料庫總管] 視窗中的 [資料表] 資料夾,然後選擇建立新的資料表。 將第一個資料行 UserId
命名為 ,並將其類型設定為 uniqueidentifier
。 不允許 NULL
值,並將資料行標示為主鍵。 接下來,新增名為: HomeTown
類型的 nvarchar(50)
資料行; HomepageUrl
類型 nvarchar(100)
為 ,而 類型 nvarchar(500)
為 的簽章。 這三個數據行中的每一個 NULL
都可以接受值。
圖 6:建立 UserProfiles
資料表 (按一下即可檢視大小完整的映射)
儲存資料表並將其命名為 UserProfiles
。 最後,在資料表欄位 UserId
與 aspnet_Users.UserId
欄位之間建立 UserProfiles
外鍵條件約束。 如同我們在 和 aspnet_Users
資料表之間 GuestbookComments
使用外鍵條件約束一樣,請刪除此條件約束串聯。 UserId
由於 中的 UserProfiles
欄位是主鍵,因此這可確保每個使用者帳戶的 UserProfiles
資料表中不會有一筆以上的記錄。 這種類型的關聯性稱為一對一。
既然我們已經建立資料模型,我們就可以使用它。 在步驟 2 和 3 中,我們將探討目前登入的使用者如何檢視和編輯其主鎮、首頁和簽章資訊。 在步驟 4 中,我們將建立已驗證使用者的介面,以將新的批註提交至來賓簿,並檢視現有的批註。
步驟 2:顯示使用者的首頁、首頁和簽章
有各種不同的方式可讓目前登入的使用者檢視和編輯他的主市、首頁和簽章資訊。 我們可以使用 TextBox 和 Label 控制項手動建立使用者介面,或者可以使用其中一個資料 Web 控制項,例如 DetailsView 控制項。 若要執行資料庫 SELECT
和 UPDATE
語句,我們可以在頁面的程式碼後置類別中撰寫 ADO.NET 程式碼,或者,使用 SqlDataSource 的宣告式方法。 在理想情況下,我們的應用程式會包含階層式架構,我們可以透過頁面的程式碼後置類別以程式設計方式叫用,或透過 ObjectDataSource 控制項以宣告方式叫用。
由於本教學課程系列著重于表單驗證、授權、使用者帳戶和角色,因此不會徹底討論這些不同的資料存取選項,或為何偏好階層式架構,而不是直接從 ASP.NET 網頁執行 SQL 語句。 我將會逐步解說使用 DetailsView 和 SqlDataSource – 最快速且最簡單的選項,但討論的概念當然可以套用至替代的 Web 控制項和資料存取邏輯。 如需在 ASP.NET 中使用資料的詳細資訊,請參閱在 ASP.NET 2.0 教學課程系列中使用資料 。
AdditionalUserInfo.aspx
開啟資料夾中的頁面 Membership
,並將 DetailsView 控制項新增至頁面,並將其 屬性設定為 UserProfile
,並清除其 ID
Width
和 Height
屬性。 展開 DetailsView 的智慧標籤,然後選擇將其系結至新的資料來源控制項。 這會啟動 DataSource 設定精靈 (請參閱圖 7) 。 第一個步驟會要求您指定資料來源類型。 因為我們要直接連線到 SecurityTutorials
資料庫,請選擇 [資料庫] 圖示,並將 ID
指定為 UserProfileDataSource
。
圖 7:新增名為 UserProfileDataSource
(的 SqlDataSource 控制項 ,以檢視大小完整的映射)
下一個畫面會提示資料庫使用。 我們已在 中 Web.config
為 SecurityTutorials
資料庫定義連接字串。 此連接字串名稱 – SecurityTutorialsConnectionString
應該位於下拉式清單中。 選取此選項,然後按 [下一步]。
圖 8:從 [Drop-Down清單 (按一下 SecurityTutorialsConnectionString
以檢視大小完整的影像)
後續畫面會要求我們指定要查詢的資料表和資料行。 UserProfiles
從下拉式清單中選擇資料表,並檢查所有資料行。
圖 9:從 UserProfiles
資料表中帶回所有資料行 (按一下即可檢視大小完整的影像)
圖 9 中的目前查詢會傳回 中的所有UserProfiles
記錄,但我們只對目前登入使用者的記錄感興趣。 若要新增 WHERE
子句,請按一下 WHERE
按鈕以顯示 [新增 WHERE
子句] 對話方塊, (請參閱圖 10) 。 您可以在這裡選取要篩選的資料行、運算子,以及篩選參數的來源。 選取 UserId
作為資料行,然後選取 「=」 作為運算子。
不幸的是,沒有內建參數來源可傳回目前登入的使用者 UserId
值。 我們必須以程式設計方式擷取此值。 因此,將 [來源] 下拉式清單設定為 [無],按一下 [新增] 按鈕以新增 參數,然後按一下 [確定]。
圖 10:在資料行上 UserId
新增篩選參數 (按一下即可檢視大小完整的影像)
按一下 [確定] 之後,您會返回圖 9 所示的畫面。 不過,這次,畫面底部的 SQL 查詢應該包含 WHERE
子句。 按 [下一步] 以移至 [測試查詢] 畫面。 您可以在這裡執行查詢並查看結果。 按一下 [完成] 以完成精靈。
完成 DataSource 設定精靈時,Visual Studio 會根據精靈中指定的設定建立 SqlDataSource 控制項。 此外,它會針對 SqlDataSource SelectCommand
所傳回的每個資料行,手動將 BoundFields 新增至 DetailsView。 不需要在 DetailsView 中顯示 UserId
欄位,因為使用者不需要知道此值。 您可以直接從 DetailsView 控制項的宣告式標記中移除此欄位,或按一下其智慧標籤中的 [編輯欄位] 連結。
此時,頁面的宣告式標記看起來應該類似下列內容:
<asp:DetailsView ID="UserProfile" runat="server"
AutoGenerateRows="False" DataKeyNames="UserId"
DataSourceID="UserProfileDataSource">
<Fields>
<asp:BoundField DataField="HomeTown" HeaderText="HomeTown"
SortExpression="HomeTown" />
<asp:BoundField DataField="HomepageUrl" HeaderText="HomepageUrl"
SortExpression="HomepageUrl" />
<asp:BoundField DataField="Signature" HeaderText="Signature"
SortExpression="Signature" />
</Fields>
</asp:DetailsView>
<asp:SqlDataSource ID="UserProfileDataSource" runat="server"
ConnectionString="<%$ ConnectionStrings:SecurityTutorialsConnectionString %>"
SelectCommand="SELECT [UserId], [HomeTown], [HomepageUrl], [Signature] FROM
[UserProfiles] WHERE ([UserId] = @UserId)">
<SelectParameters>
<asp:Parameter Name="UserId" Type="Object" />
</SelectParameters>
</asp:SqlDataSource>
我們需要以程式設計方式將 SqlDataSource 控制項的參數 UserId
設定為目前登入使用者的 UserId
參數,然後再選取資料。 這可以藉由建立 SqlDataSource 事件的 Selecting
事件處理常式,並在該處新增下列程式碼來完成:
protected void UserProfileDataSource_Selecting(object sender,
SqlDataSourceSelectingEventArgs e)
{
// Get a reference to the currently logged on user
MembershipUser currentUser = Membership.GetUser();
// Determine the currently logged on user's UserId value
Guid currentUserId = (Guid)currentUser.ProviderUserKey;
// Assign the currently logged on user's UserId to the @UserId parameter
e.Command.Parameters["@UserId"].Value = currentUserId;
}
上述程式碼會藉由呼叫 Membership
類別 GetUser
的 方法,取得目前登入使用者的參考開始。 這會傳 MembershipUser
回 物件,其 ProviderUserKey
屬性包含 UserId
。 然後,此值 UserId
會指派給 SqlDataSource 的參數 @UserId
。
注意
方法 Membership.GetUser()
會傳回目前登入使用者的相關資訊。 如果匿名使用者正在流覽頁面,則會傳回 的值 null
。 在這種情況下,這會在嘗試讀取 ProviderUserKey
屬性時, NullReferenceException
在下列程式程式碼上導致 。 當然,我們不需要擔心 Membership.GetUser()
在頁面中傳 null
回值,因為我們已在上一個教學課程中 AdditionalUserInfo.aspx
設定 URL 授權,因此只有已驗證的使用者才能存取此資料夾中的 ASP.NET 資源。 如果您需要在允許匿名存取的頁面存取目前登入使用者的相關資訊,請務必在參考其屬性之前,先檢查方法是否傳回 GetUser()
非 null MembershipUser
物件。
如果您透過瀏覽器流覽 AdditionalUserInfo.aspx
頁面,您會看到空白頁面,因為我們尚未將任何資料列新增至 UserProfiles
資料表。 在步驟 6 中,我們將探討如何自訂 CreateUserWizard 控制項,以在建立新的使用者帳戶時自動將新資料列新增至 UserProfiles
資料表。 不過,我們現在必須手動在資料表中建立記錄。
流覽至 Visual Studio 中的 [資料庫總管],然後展開 [資料表] 資料夾。 以滑鼠右鍵按一下 aspnet_Users
資料表,然後選擇 [顯示資料表資料] 以查看資料表中的記錄;對 UserProfiles
資料表執行相同的動作。 圖 11 顯示垂直並排時的結果。 我的資料庫中目前 aspnet_Users
有 Bruce、Fred 和 Tito 的記錄,但資料表中 UserProfiles
沒有記錄。
圖 11:和 UserProfiles
資料表的內容 aspnet_Users
會顯示 (按一下即可檢視大小完整的影像)
手動輸入 、 HomepageUrl
和 Signature
欄位的值 HomeTown
,將新記錄新增至 UserProfiles
資料表。 取得新 UserProfiles
記錄中有效 UserId
值最簡單的方式,就是從資料表中的特定使用者帳戶 aspnet_Users
選取 UserId
欄位,然後將它複製並貼到 UserId
中的 UserProfiles
欄位中。 圖 12 顯示 UserProfiles
針對 Bruce 新增記錄之後的資料表。
圖 12:已針對暴力密碼新增 UserProfiles
記錄 (按一下即可檢視完整大小的影像)
AdditionalUserInfo.aspx
返回頁面,以暴力密碼登入。 如圖 13 所示,會顯示暴力密碼的設定。
圖 13:目前流覽的使用者會顯示其設定 (按一下以檢視完整大小的影像)
注意
請繼續並手動為每個成員資格使用者新增資料表中的 UserProfiles
記錄。 在步驟 6 中,我們將探討如何自訂 CreateUserWizard 控制項,以在建立新的使用者帳戶時自動將新的資料列新增至 UserProfiles
資料表。
步驟 3:允許使用者編輯他的主鎮、首頁和簽章
此時,目前登入的使用者可以檢視其住家城市、首頁和簽章設定,但還無法加以修改。 讓我們更新 DetailsView 控制項,以便編輯資料。
我們需要做的第一件事是為 SqlDataSource 新增 , UpdateCommand
並 UPDATE
指定要執行的語句及其對應的參數。 選取 SqlDataSource,然後從屬性視窗按一下 UpdateQuery 屬性旁邊的省略號,以顯示 [命令和參數編輯器] 對話方塊。 在文字方塊中輸入下列 UPDATE
語句:
UPDATE UserProfiles SET
HomeTown = @HomeTown,
HomepageUrl = @HomepageUrl,
Signature = @Signature
WHERE UserId = @UserId
接下來,按一下 [重新整理參數] 按鈕,這會在 SqlDataSource 控制項的 UpdateParameters
集合中為 語句中的每個 UPDATE
參數建立參數。 將所有參數的來源保留為 [無],然後按一下 [確定] 按鈕以完成對話方塊。
圖 14:指定 SqlDataSource 的 UpdateCommand
和 UpdateParameters
(按一下即可檢視完整大小的影像)
由於我們新增至 SqlDataSource 控制項,DetailsView 控制項現在可以支援編輯。 從 DetailsView 的智慧標籤中,核取 [啟用編輯] 核取方塊。 這會將 CommandField 新增至控制項的集合, Fields
並將其 ShowEditButton
屬性設定為 True。 當 DetailsView 以唯讀模式顯示時,這會轉譯 [編輯] 按鈕,並在編輯模式中顯示 [更新] 和 [取消] 按鈕時呈現。 不過,我們不需要使用者按一下 [編輯],而是可以將 DetailsView 控制項的DefaultMode
屬性設定為 Edit
,讓 DetailsView 轉譯處於「永遠可編輯」狀態。
有了這些變更,您的 DetailsView 控制項的宣告式標記看起來應該如下所示:
<asp:DetailsView ID="UserProfile" runat="server"
AutoGenerateRows="False" DataKeyNames="UserId"
DataSourceID="UserProfileDataSource" DefaultMode="Edit">
<Fields>
<asp:BoundField DataField="HomeTown" HeaderText="HomeTown"
SortExpression="HomeTown" />
<asp:BoundField DataField="HomepageUrl" HeaderText="HomepageUrl"
SortExpression="HomepageUrl" />
<asp:BoundField DataField="Signature" HeaderText="Signature"
SortExpression="Signature" />
<asp:CommandField ShowEditButton="True" />
</Fields>
</asp:DetailsView>
請注意新增 CommandField 和 DefaultMode
屬性。
繼續並透過瀏覽器測試此頁面。 使用 中 UserProfiles
具有對應記錄的使用者流覽時,使用者的設定會顯示在可編輯的介面中。
圖 15:DetailsView 轉譯可編輯的介面 (按一下即可檢視完整大小的影像)
請嘗試變更值,然後按一下 [更新] 按鈕。 看起來就像沒有發生任何事一樣。 有回傳,且值會儲存至資料庫,但沒有發生儲存的視覺回饋。
若要解決此問題,請返回 Visual Studio,並在 DetailsView 上方新增標籤控制項。 將其 ID
設定為 SettingsUpdatedMessage
、其 Text
屬性設定為 [已更新您的設定],並將其 Visible
和 EnableViewState
屬性設定為 false
。
<asp:Label ID="SettingsUpdatedMessage" runat="server"
Text="Your settings have been updated."
EnableViewState="false"
Visible="false"></asp:Label>
每當 DetailsView 更新時,我們需要顯示 SettingsUpdatedMessage
標籤。 若要達成此目的,請建立 DetailsView ItemUpdated
事件的事件處理常式,並新增下列程式碼:
protected void UserProfile_ItemUpdated(object sender, DetailsViewUpdatedEventArgs e)
{
SettingsUpdatedMessage.Visible = true;
}
透過瀏覽器返回 AdditionalUserInfo.aspx
頁面並更新資料。 這次會顯示有用的狀態訊息。
圖 16:當 [設定更新] (按一下以檢視完整大小的影像 時,會顯示簡短訊息)
注意
DetailsView 控制項的編輯介面會留下許多需要。 它會使用標準大小的文字方塊,但 [簽章] 欄位應該是多行文字方塊。 RegularExpressionValidator 應該用來確保輸入的首頁 URL 開頭為 「HTTP://」 或 「HTTPs://」。 此外,由於 DetailsView 控制項的 DefaultMode
屬性設定為 Edit
,因此 [取消] 按鈕不會執行任何動作。 應該移除或按一下時,將使用者重新導向至其他頁面 (,例如 ~/Default.aspx
) 。 我將這些增強功能保留為讀者的練習。
在主版頁面中新增頁面的連結 AdditionalUserInfo.aspx
網站目前未提供頁面的任何連結 AdditionalUserInfo.aspx
。 連線的唯一方法是直接在瀏覽器的網址列中輸入頁面的 URL。 讓我們在主版頁面中新增此頁面 Site.master
的連結。
回想一下,主版頁面在其 LoginContent
ContentPlaceHolder 中包含 LoginView Web 控制項,可針對已驗證和匿名訪客顯示不同的標記。 更新 LoginView 控制項的 LoggedInTemplate
,以包含頁面的連結 AdditionalUserInfo.aspx
。 進行這些變更之後,LoginView 控制項的宣告式標記看起來應該如下所示:
<asp:LoginView ID="LoginView1" runat="server">
<LoggedInTemplate>
Welcome back,
<asp:LoginName ID="LoginName1" runat="server" />.
<br />
<asp:HyperLink ID="lnkUpdateSettings" runat="server"
NavigateUrl="~/Membership/AdditionalUserInfo.aspx">
Update Your Settings</asp:HyperLink>
</LoggedInTemplate>
<AnonymousTemplate>
Hello, stranger.
</AnonymousTemplate>
</asp:LoginView>
請注意將 HyperLink 控制項新增 lnkUpdateSettings
至 LoggedInTemplate
。 透過此連結,已驗證的使用者可以快速跳至頁面,以檢視和修改其住家城市、首頁和簽章設定。
步驟 4:新增客體簿批註
此頁面 Guestbook.aspx
是經驗證的使用者可檢視來賓簿並留下批註的位置。 讓我們從建立 介面開始,以新增客體簿批註。
Guestbook.aspx
在 Visual Studio 中開啟頁面,並建構由兩個 TextBox 控制群組成的使用者介面,一個用於新批註的主旨,另一個用於其本文。 將第一個 TextBox 控制項的 ID
屬性設定為 Subject
,並將其 Columns
屬性設定為 40;將第二個 ID
的 設定為 Body
,並將其 TextMode
設定為 MultiLine
,並將其 Width
和 Rows
屬性分別設定為 「95%」 和 8。 若要完成使用者介面,請新增名為 PostCommentButton
的 Button Web 控制項,並將其 Text
屬性設定為 [張貼您的批註]。
由於每個來賓簿批註都需要主旨和本文,因此請為每個 TextBoxes 新增 RequiredFieldValidator。 ValidationGroup
將這些控制項的 屬性設定為 「EnterComment」,同樣地,將 PostCommentButton
控制項的 ValidationGroup
屬性設定為 「EnterComment」。 如需 ASP 的詳細資訊。NET 的驗證控制項,請參閱 ASP.NET 中的表單驗證。
製作使用者介面之後,頁面的宣告式標記看起來應該如下所示:
<h3>Leave a Comment</h3>
<p>
<b>Subject:</b>
<asp:RequiredFieldValidator ID="SubjectReqValidator" runat="server"
ErrorMessage="You must provide a value for Subject"
ControlToValidate="Subject" ValidationGroup="EnterComment">
</asp:RequiredFieldValidator><br/>
<asp:TextBox ID="Subject" Columns="40" runat="server"></asp:TextBox>
</p>
<p>
<b>Body:</b>
<asp:RequiredFieldValidator ID="BodyReqValidator" runat="server"
ControlToValidate="Body"
ErrorMessage="You must provide a value for Body" ValidationGroup="EnterComment">
</asp:RequiredFieldValidator><br/>
<asp:TextBox ID="Body" TextMode="MultiLine" Width="95%"
Rows="8" runat="server"></asp:TextBox>
</p>
<p>
<asp:Button ID="PostCommentButton" runat="server"
Text="Post Your Comment"
ValidationGroup="EnterComment" />
</p>
完成使用者介面之後,下一項工作是在按一下 時 PostCommentButton
,將新記錄 GuestbookComments
插入資料表中。 這可以透過數種方式來完成:我們可以在 Button 的 Click
事件處理常式中撰寫 ADO.NET 程式碼;我們可以將 SqlDataSource 控制項新增至頁面、設定其 ,然後從 Click
Click
事件處理常式呼叫其 InsertCommand
Insert
方法;或者,我們可以建置負責插入新客體批註的仲介層,並從事件處理常式叫用這項功能。 因為我們在步驟 3 中使用 SqlDataSource,讓我們在這裡使用 ADO.NET 程式碼。
注意
用來以程式設計方式存取 Microsoft SQL Server 資料庫中資料的 ADO.NET 類別位於 命名空間中 System.Data.SqlClient
。 您可能需要將此命名空間匯入頁面的程式碼後置類別 (亦即 using System.Data.SqlClient;
) 。
建立 事件的 Click
事件處理常式 PostCommentButton
,並新增下列程式碼:
protected void PostCommentButton_Click(object sender, EventArgs e)
{
if (!Page.IsValid)
return;
// Determine the currently logged on user's UserId
MembershipUser currentUser = Membership.GetUser();
Guid currentUserId = (Guid)currentUser.ProviderUserKey;
// Insert a new record into GuestbookComments
string connectionString =
ConfigurationManager.ConnectionStrings["SecurityTutorialsConnectionString"].ConnectionString;
string insertSql = "INSERT INTO GuestbookComments(Subject, Body, UserId) VALUES(@Subject,
@Body, @UserId)";
using (SqlConnection myConnection = new SqlConnection(connectionString))
{
myConnection.Open();
SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
myCommand.Parameters.AddWithValue("@Subject", Subject.Text.Trim());
myCommand.Parameters.AddWithValue("@Body", Body.Text.Trim());
myCommand.Parameters.AddWithValue("@UserId", currentUserId);
myCommand.ExecuteNonQuery();
myConnection.Close();
}
// "Reset" the Subject and Body TextBoxes
Subject.Text = string.Empty;
Body.Text = string.Empty;
}
Click
事件處理常式會從檢查使用者提供的資料是否有效開始。 如果不是,事件處理常式會在插入記錄之前結束。 假設提供的資料有效,則會擷取目前登入使用者 UserId
的值,並儲存在區域變數中 currentUserId
。 需要這個值,因為我們必須在將記錄插入 時 GuestbookComments
提供 UserId
值。
接著,會從 Web.config
擷取資料庫的連接字串 SecurityTutorials
,並 INSERT
指定 SQL 語句。 SqlConnection
然後會建立並開啟 物件。 接下來,會 SqlCommand
建構 物件,並指派查詢中使用的 INSERT
參數值。 接著會 INSERT
執行 語句,並關閉連接。 在事件處理常式結束時, Subject
會清除 和 Body
TextBoxes Text
的屬性,讓使用者的值不會在回傳中保存。
繼續並在瀏覽器中測試此頁面。 由於此頁面位於 Membership
資料夾中,因此匿名訪客無法存取。 因此,如果您尚未) ,您必須先登入 (。 在 和 Body
TextBox 中輸入值 Subject
,然後按一下 PostCommentButton
按鈕。 這會導致將新記錄新增至 GuestbookComments
。 在回傳時,您提供的主體和本文會從 TextBox 抹除。
按一下 PostCommentButton
按鈕之後,沒有將批註新增至來賓簿的視覺化意見反應。 我們仍然需要更新此頁面,以顯示我們將在步驟 5 中執行的現有客體簿批註。 一旦完成此動作,剛加入的批註會出現在批註清單中,並提供適當的視覺回饋。 現在,檢查資料表的內容 GuestbookComments
,確認您的來賓簿批註已儲存。
圖 17 顯示離開兩個批註之後的資料表內容 GuestbookComments
。
圖 17:您可以在資料表中看到 GuestbookComments
客體簿批註, (按一下即可檢視完整大小的影像)
注意
如果使用者嘗試插入包含潛在危險標記的來賓簿批註,例如 HTML – ASP.NET 將會擲回 HttpRequestValidationException
。 若要深入瞭解此例外狀況,為何擲回此例外狀況,以及如何允許使用者提交潛在危險值,請參閱 要求驗證白皮書。
步驟 5:列出現有的來賓簿批註
除了留下批註之外,流覽 Guestbook.aspx
頁面的使用者也應該能夠檢視來賓簿的現有批註。 若要達成此目的,請將名為 CommentList
的 ListView 控制項新增至頁面底部。
注意
ListView 控制項是 ASP.NET 3.5 版的新功能。 其設計目的是要以非常可自訂且彈性的版面配置顯示專案清單,但仍提供內建編輯、插入、刪除、分頁和排序功能,例如 GridView。 如果您使用 ASP.NET 2.0,則必須改用 DataList 或 Repeater 控制項。 如需使用 ListView 的詳細資訊,請參閱 Scott Guthrie的部落格文章 :asp:ListView 控制項和我的文章: 使用 ListView 控制項顯示資料。
開啟 ListView 的智慧標籤,然後從 [選擇資料來源] 下拉式清單中,將控制項系結至新的資料來源。 如我們在步驟 2 中所見,這會啟動 [資料來源設定精靈]。 選取 [資料庫] 圖示,將產生的 SqlDataSource CommentsDataSource
命名為 ,然後按一下 [確定]。 接下來,從下拉式清單中選取 SecurityTutorialsConnectionString
連接字串,然後按 [下一步]。
此時,在步驟 2 中,我們會從下拉式清單中挑選 UserProfiles
資料表,然後選取要傳回的資料行,以傳回 (參考圖 9) 來指定要查詢的資料。 不過,這次我們想要製作一個 SQL 語句,其不僅會從 GuestbookComments
提取記錄,還會製作批註者的主市、首頁、簽章和使用者名稱。 因此,選取 [指定自訂 SQL 語句或預存程式] 選項按鈕,然後按 [下一步]。
這會顯示 [定義自訂語句或預存程式] 畫面。 按一下 [查詢產生器] 按鈕以圖形方式建置查詢。 查詢產生器會從提示我們指定我們想要查詢的資料表開始。 GuestbookComments
選取 、 UserProfiles
和 aspnet_Users
資料表,然後按一下 [確定]。 這會將這三個數據表新增至設計介面。 由於 、 UserProfiles
和 aspnet_Users
資料表之間 GuestbookComments
有外鍵條件約束,因此查詢產生器會自動 JOIN
設定這些資料表。
所有保留專案都是指定要傳回的資料行。 GuestbookComments
從資料表中 Subject
選取 、 Body
和 CommentDate
資料行;從資料表傳 HomeTown
回 、 HomepageUrl
和 Signature
UserProfiles
資料行;並從 傳 aspnet_Users
回 UserName
。 此外,將 「 ORDER BY CommentDate DESC
」 新增至查詢結尾 SELECT
,以便先傳回最新的文章。 進行這些選取之後,您的查詢產生器介面看起來應該類似圖 18 中的螢幕擷取畫面。
圖 18:建構的查詢 JOIN
(aspnet_Users
GuestbookComments
UserProfiles
按一下即可檢視大小完整的映射)
按一下 [確定] 關閉 [查詢產生器] 視窗,並返回 [定義自訂語句或預存程式] 畫面。 按一下 [下一步] 以前進到 [測試查詢] 畫面,您可以按一下 [測試查詢] 按鈕來檢視查詢結果。 當您準備好時,按一下 [完成] 以完成 [設定資料來源精靈]。
當我們在步驟 2 中完成設定資料來源精靈時,相關聯的 DetailsView 控制項 Fields
集合已更新,以包含 所傳回之每個資料行的 SelectCommand
BoundField。 不過,ListView 會保持不變;我們仍然需要定義其配置。 ListView 的版面配置可以透過其宣告式標記或從其智慧標籤中的 [設定 ListView] 選項手動建構。 我通常偏好手動定義標記,但使用您最自然的方法。
我最後會針對我的 ListView 控制項使用下列 LayoutTemplate
、 ItemTemplate
和 ItemSeparatorTemplate
:
<asp:ListView ID="CommentList" runat="server" DataSourceID="CommentsDataSource">
<LayoutTemplate>
<span ID="itemPlaceholder" runat="server" />
<p>
<asp:DataPager ID="DataPager1" runat="server">
<Fields>
<asp:NextPreviousPagerField ButtonType="Button"
ShowFirstPageButton="True"
ShowLastPageButton="True" />
</Fields>
</asp:DataPager>
</p>
</LayoutTemplate>
<ItemTemplate>
<h4><asp:Label ID="SubjectLabel" runat="server"
Text='<%# Eval("Subject") %>' /></h4>
<asp:Label ID="BodyLabel" runat="server"
Text='<%# Eval("Body").ToString().Replace(Environment.NewLine, "<br />") %>' />
<p>
---<br />
<asp:Label ID="SignatureLabel" Font-Italic="true" runat="server"
Text='<%# Eval("Signature") %>' />
<br />
<br />
My Home Town:
<asp:Label ID="HomeTownLabel" runat="server"
Text='<%# Eval("HomeTown") %>' />
<br />
My Homepage:
<asp:HyperLink ID="HomepageUrlLink" runat="server"
NavigateUrl='<%# Eval("HomepageUrl") %>'
Text='<%# Eval("HomepageUrl") %>' />
</p>
<p align="center">
Posted by
<asp:Label ID="UserNameLabel" runat="server"
Text='<%# Eval("UserName") %>' /> on
<asp:Label ID="CommentDateLabel" runat="server"
Text='<%# Eval("CommentDate") %>' />
</p>
</ItemTemplate>
<ItemSeparatorTemplate>
<hr />
</ItemSeparatorTemplate>
</asp:ListView>
會 LayoutTemplate
定義 控制項所發出的標記,而 會 ItemTemplate
轉譯 SqlDataSource 傳回的每個專案。 產生的 ItemTemplate
標記會放在 的 itemPlaceholder
控制項中 LayoutTemplate
。 除了 itemPlaceholder
之外,還 LayoutTemplate
包含 DataPager 控制項,其會限制 ListView 只顯示每個頁面 10 個來賓簿批註, (預設) 並轉譯分頁介面。
我在 ItemTemplate
主體下方的元素中 <h4>
顯示每個來賓簿批註的主旨。 請注意,用來顯示本文的語法會採用 databinding 語句所 Eval("Body")
傳回的資料、將它轉換成字串,並以 元素取代分行符號 <br />
。 需要此轉換,才能顯示提交批註時輸入的分行符號,因為 HTML 會忽略空白字元。 使用者的簽章會顯示在斜體下方,後面接著使用者的首頁、首頁的連結、建立批註的日期和時間,以及離開批註的人員使用者名稱。
請花點時間透過瀏覽器檢視頁面。 您應該會在此處顯示的步驟 5 中看到您新增至來賓簿的批註。
圖 19: Guestbook.aspx
現在顯示客體簿的批註 (按一下即可檢視大小完整的影像)
請嘗試將新的批註新增至來賓簿。 按一下 PostCommentButton
頁面回傳的按鈕,並將批註新增至資料庫,但 ListView 控制項不會更新以顯示新的批註。 這可由下列任一項修正:
PostCommentButton
更新按鈕的Click
事件處理常式,讓它在將新的批註插入資料庫之後叫用 ListView 控制項DataBind()
的 方法,或- 將 ListView 控制項的
EnableViewState
屬性設定為false
。 此方法的運作方式是藉由停用控制項的檢視狀態,因此必須重新系結至每個回傳的基礎資料。
本教學課程中可下載的教學課程網站說明這兩種技術。 ListView 控制項的 EnableViewState
屬性 false
和以程式設計方式將資料重新系結至 ListView 所需的程式碼會存在於事件處理常式中 Click
,但已批註化。
注意
AdditionalUserInfo.aspx
目前頁面可讓使用者檢視和編輯其主市、首頁和簽章設定。 更新 AdditionalUserInfo.aspx
可能會很適合用來顯示已登入使用者的來賓簿批註。 也就是說,除了檢查和修改其資訊之外,使用者可以流覽 AdditionalUserInfo.aspx
頁面,以查看過去所做的來賓簿批註。 我將此保留為感興趣的讀者練習。
步驟 6:自訂 CreateUserWizard 控制項以包含主鎮、首頁和簽章的介面
SELECT
頁面所使用的 Guestbook.aspx
查詢會使用 來 INNER JOIN
結合 、 UserProfiles
和 aspnet_Users
資料表之間的 GuestbookComments
相關記錄。 如果 中 UserProfiles
沒有記錄的使用者提出來賓簿批註,則批註將不會顯示在 ListView 中,因為 INNER JOIN
只有在 和 aspnet_Users
中有 UserProfiles
相符的記錄時,才會傳回 GuestbookComments
記錄。 如同我們在步驟 3 中所見,如果使用者在頁面中沒有記錄 UserProfiles
,則無法檢視或編輯其設定 AdditionalUserInfo.aspx
。
不需要說,由於我們的設計決策,成員資格系統中的每一個使用者帳戶都有資料表中的 UserProfiles
相符記錄非常重要。 每當透過 CreateUserWizard 建立新的成員資格使用者帳戶時,我們想要將對應的記錄加入 UserProfiles
其中。
如建立使用者帳戶教學課程中所述,建立新的成員資格使用者帳戶之後,CreateUserWizard 控制項會引發其CreatedUser
事件。 我們可以為此事件建立事件處理常式、取得剛建立使用者的 UserId,然後將記錄 UserProfiles
插入具有 、 HomepageUrl
和 資料 Signature
行預設值的 HomeTown
資料表中。 此外,您可以藉由自訂 CreateUserWizard 控制項的介面來包含其他 TextBox,來提示使用者輸入這些值。
讓我們先看看如何使用預設值,將新的資料列新增至 UserProfiles
事件處理常式中的 CreatedUser
資料表。 接下來,我們將瞭解如何自訂 CreateUserWizard 控制項的使用者介面,以包含其他表單欄位來收集新使用者的主市、首頁和簽章。
將預設資料列新增至UserProfiles
在 建立使用者帳戶 教學課程中,我們已將 CreateUserWizard 控制項新增至 CreatingUserAccounts.aspx
資料夾中的頁面 Membership
。 若要讓 CreateUserWizard 控制項在使用者帳戶建立時將記錄新增至 UserProfiles
資料表,我們需要更新 CreateUserWizard 控制項的功能。 讓我們改為將新的 CreateUserWizard 控制項新增至 EnhancedCreateUserWizard.aspx
頁面,並在該處修改本教學課程,而不是對這些頁面進行這些變更 CreatingUserAccounts.aspx
。
EnhancedCreateUserWizard.aspx
在 Visual Studio 中開啟頁面,並將 CreateUserWizard 控制項從 [工具箱] 拖曳至頁面。 將 CreateUserWizard 控制項的 ID
屬性設定為 NewUserWizard
。 如同我們在建立使用者帳戶教學課程中所 討論,CreateUserWizard 的預設使用者介面會提示訪客輸入必要的資訊。 提供此資訊之後,控制項會在內部在成員資格架構中建立新的使用者帳戶,完全不需要撰寫單行程式碼。
CreateUserWizard 控制項在其工作流程期間引發一些事件。 訪客提供要求資訊並提交表單之後,CreateUserWizard 控制項一開始會引發其CreatingUser
事件。 如果在建立過程中發生問題,就會CreateUserError
引發事件;不過,如果成功建立使用者,則會CreatedUser
引發事件。 在建立 使用者帳戶教學課程中,我們建立了 CreatingUser
事件的事件處理常式,以確保提供的使用者名稱不包含任何前置或尾端空格,而且使用者名稱未出現在密碼中的任何位置。
為了在資料表中 UserProfiles
為剛建立的使用者新增資料列,我們需要為 CreatedUser
事件建立事件處理常式。 在引發事件時 CreatedUser
,已在成員資格架構中建立使用者帳戶,讓我們能夠擷取帳戶的 UserId 值。
建立 NewUserWizard
事件的 CreatedUser
事件處理常式,並新增下列程式碼:
protected void NewUserWizard_CreatedUser(object sender, EventArgs e)
{
// Get the UserId of the just-added user
MembershipUser newUser = Membership.GetUser(NewUserWizard.UserName);
Guid newUserId = (Guid)newUser.ProviderUserKey;
// Insert a new record into UserProfiles
string connectionString =
ConfigurationManager.ConnectionStrings["SecurityTutorialsConnectionString"].ConnectionString;
string insertSql = "INSERT INTO UserProfiles(UserId, HomeTown, HomepageUrl,
Signature) VALUES(@UserId, @HomeTown, @HomepageUrl, @Signature)";
using (SqlConnection myConnection = new SqlConnection(connectionString))
{
myConnection.Open();
SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
myCommand.Parameters.AddWithValue("@UserId", newUserId);
myCommand.Parameters.AddWithValue("@HomeTown", DBNull.Value);
myCommand.Parameters.AddWithValue("@HomepageUrl", DBNull.Value);
myCommand.Parameters.AddWithValue("@Signature", DBNull.Value);
myCommand.ExecuteNonQuery();
myConnection.Close();
}
}
上述程式碼是藉由擷取剛新增使用者帳戶的 UserId。 這是使用 Membership.GetUser(username)
方法來傳回特定使用者的相關資訊,然後使用 ProviderUserKey
屬性來擷取其 UserId 來完成。 CreateUserWizard 控制項中使用者輸入的使用者名稱可透過其UserName
屬性取得。
接下來,會從 Web.config
擷取連接字串, INSERT
並指定 語句。 必要的 ADO.NET 物件會具現化並執行命令。 程式碼會將 DBNull
實例指派給 @HomeTown
、 @HomepageUrl
和 @Signature
參數,其效果是插入 、 HomepageUrl
和 Signature
欄位的資料庫 NULL
值 HomeTown
。
EnhancedCreateUserWizard.aspx
流覽瀏覽器的頁面,並建立新的使用者帳戶。 執行此動作之後,返回 Visual Studio 並檢查 和 UserProfiles
資料表的內容 aspnet_Users
(,就像我們在圖 12 中) 一樣。 您應該會在 中看到 aspnet_Users
新的使用者帳戶,以及具有 NULL
、 HomepageUrl
和 Signature
) 值的 HomeTown
對應 UserProfiles
資料列 (。
圖 20:已新增新的使用者帳戶和 UserProfiles
記錄, (按一下即可檢視大小完整的映射)
在訪客提供新的帳戶資訊並按一下 [建立使用者] 按鈕之後,就會建立使用者帳戶,並將一個資料列新增至 UserProfiles
資料表。 CreateUserWizard 接著會顯示其 CompleteWizardStep
,其中會顯示成功訊息和 [繼續] 按鈕。 按一下 [繼續] 按鈕會導致回傳,但不會採取任何動作,讓使用者停留在 EnhancedCreateUserWizard.aspx
頁面上。
我們可以指定 URL,以透過 CreateUserWizard 控制項的ContinueDestinationPageUrl
屬性按一下 [繼續] 按鈕時,將使用者傳送至 。 將 ContinueDestinationPageUrl
屬性設定為 「~/Membership/AdditionalUserInfo.aspx」。 這會讓新使用者前往 AdditionalUserInfo.aspx
,讓他們可以在其中檢視和更新其設定。
自訂 CreateUserWizard 的介面,以提示新使用者的主市、首頁和簽章
CreateUserWizard 控制項的預設介面足以用於簡單的帳戶建立案例,其中只需要收集核心使用者帳戶資訊,例如使用者名稱、密碼和電子郵件。 但是,如果我們想要提示訪客在建立她的帳戶時進入她的主市、首頁和簽章,該怎麼辦? 您可以自訂 CreateUserWizard 控制項的介面,以在註冊時收集其他資訊,而且此資訊可用於事件處理常式, CreatedUser
將其他記錄插入基礎資料庫中。
CreateUserWizard 控制項會擴充 ASP.NET Wizard 控制項,這是一個控制項,可讓頁面開發人員定義一系列的已排序 WizardSteps
。 精靈控制項會轉譯使用中的步驟,並提供導覽介面,讓訪客可以流覽這些步驟。 精靈控制項很適合用來將長任務細分成數個簡短步驟。 如需精靈控制項的詳細資訊,請參閱 使用 ASP.NET 2.0 精靈控制項建立逐步使用者介面。
CreateUserWizard 控制項的預設標記會定義兩 WizardSteps
個 : CreateUserWizardStep
和 CompleteWizardStep
。
<asp:CreateUserWizard ID="NewUserWizard" runat="server"
ContinueDestinationPageUrl="~/Membership/AdditionalUserInfo.aspx">
<WizardSteps>
<asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
</asp:CreateUserWizardStep>
<asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
</asp:CompleteWizardStep>
</WizardSteps>
</asp:CreateUserWizard>
第一個 WizardStep
會 CreateUserWizardStep
轉譯提示輸入使用者名稱、密碼、電子郵件等的介面。 訪客提供這項資訊並按一下 [建立使用者] 之後,她會顯示 CompleteWizardStep
,其中顯示成功訊息和 [繼續] 按鈕。
若要自訂 CreateUserWizard 控制項的介面以包含其他表單欄位,我們可以:
建立一或多個新
WizardStep
,包含額外的使用者介面專案。 若要將新的WizardStep
新增至 CreateUserWizard,請按一下其智慧標籤中的 [新增/移除WizardSteps
] 連結,以啟動WizardStep
集合編輯器。 您可以從該處新增、移除或重新排序精靈中的步驟。 這是我們將在本教學課程中使用的方法。CreateUserWizardStep
轉換進入可WizardStep
編輯.這會以對等WizardStep
專案取代 ,CreateUserWizardStep
其標記會定義符合CreateUserWizardStep
之 的使用者介面。 藉由將CreateUserWizardStep
轉換成 ,WizardStep
我們可以重新置放控制項,或將其他使用者介面元素新增至此步驟。 若要將CreateUserWizardStep
或CompleteWizardStep
轉換成可WizardStep
編輯的 ,請按一下控制項智慧標籤中的 [自訂建立使用者步驟] 或 [自訂完成步驟] 連結。使用上述兩個選項的一些組合。
請務必記住,CreateUserWizard 控制項會在按一下 [建立使用者] 按鈕 CreateUserWizardStep
時執行其使用者帳戶建立程式。 如果 之後有額外的 WizardStep
CreateUserWizardStep
,則不重要。
將自訂 WizardStep
新增至 CreateUserWizard 控制項以收集其他使用者輸入時,可以在 之前或之後 CreateUserWizardStep
放置自訂 WizardStep
。 如果它出現在 之前 CreateUserWizardStep
,則從自訂 WizardStep
收集的額外使用者輸入可供事件處理常式使用 CreatedUser
。 不過,如果自訂 WizardStep
在之後 CreateUserWizardStep
,在顯示自訂 WizardStep
時,已經建立新的使用者帳戶,而且 CreatedUser
事件已經引發。
圖 21 顯示新增之前加入 WizardStep
的 CreateUserWizardStep
工作流程。 由於事件引發時 CreatedUser
已收集其他使用者資訊,因此我們只需要更新 CreatedUser
事件處理常式來擷取這些輸入,並使用這些輸入作為 INSERT
語句的參數值 (,而不是 DBNull.Value
) 。
圖 21:當其他 WizardStep
專案在 (之前 CreateUserWizardStep
按一下 以檢視完整大小的影像 時,CreateUserWizard 工作流程)
不過,如果在之後CreateUserWizardStep
放置自訂 WizardStep
,則建立使用者帳戶程式會在使用者有機會進入她的家庭城市、首頁或簽章之前發生。 在這種情況下,這個額外的資訊必須在使用者帳戶建立之後插入資料庫,如圖 22 所示。
圖 22:當其他專案出現在 (按一下以CreateUserWizardStep
檢視完整大小的影像時 WizardStep
,CreateUserWizard 工作流程)
圖 22 中顯示的工作流程會等候將記錄插入資料表, UserProfiles
直到步驟 2 完成為止。 不過,如果訪客在步驟 1 之後關閉瀏覽器,我們就會到達使用者帳戶建立的狀態,但未將任何記錄新增至 UserProfiles
。 其中一個因應措施是在事件處理常式中 CreatedUser
插入 UserProfiles
或預設值的記錄 NULL
, (在步驟 1) 之後引發,然後在步驟 2 完成之後更新此記錄。 這可確保 UserProfiles
即使使用者于中間結束註冊程式,也會為使用者帳戶新增記錄。
在本教學課程中,我們將建立新的 WizardStep
,其發生在 之後 CreateUserWizardStep
,但在 之前 CompleteWizardStep
。 讓我們先就地取得 WizardStep 並加以設定,然後查看程式碼。
從 CreateUserWizard 控制項的智慧標籤中,選取 [新增/移除 WizardStep
s],這會顯示 WizardStep
[集合編輯器] 對話方塊。 將新的 WizardStep
新增 ,將其 ID
設定為 UserSettings
,並將其 Title
設定為 [您的設定],並將其 StepType
設定為 Step
。 然後將它 CreateUserWizardStep
放在 (「註冊新帳戶」) 之後,以及 (「完成」) 之前 CompleteWizardStep
,如圖 23 所示。
圖 23:新增 WizardStep
至 CreateUserWizard 控制項 (按一下即可檢視完整大小的影像)
按一下 [確定] 以關閉 [ WizardStep
集合編輯器] 對話方塊。 New WizardStep
是由 CreateUserWizard 控制項更新的宣告式標記所辨識:
<asp:CreateUserWizard ID="NewUserWizard" runat="server"
ContinueDestinationPageUrl="~/Membership/AdditionalUserInfo.aspx">
<WizardSteps>
<asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
</asp:CreateUserWizardStep>
<asp:WizardStep runat="server" ID="UserSettings" StepType="Step"
Title="Your Settings">
</asp:WizardStep>
<asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
</asp:CompleteWizardStep>
</WizardSteps>
</asp:CreateUserWizard>
請注意新的 <asp:WizardStep>
專案。 我們需要新增使用者介面,以在這裡收集新使用者的主市、首頁和簽章。 您可以在宣告式語法中或透過Designer輸入此內容。 若要使用Designer,請從智慧標籤的下拉式清單中選取 [您的設定] 步驟,以查看Designer中的步驟。
注意
選取智慧標籤下拉式清單的步驟會更新 CreateUserWizard 控制項的ActiveStepIndex
屬性,指定起始步驟的索引。 因此,如果您使用此下拉式清單來編輯Designer中的 [您的設定] 步驟,請務必將它設回 「註冊您的新帳戶」,以便在使用者第一次流覽 EnhancedCreateUserWizard.aspx
頁面時顯示此步驟。
在 「您的設定」步驟內建立使用者介面,其中包含三個名為 HomeTown
、 HomepageUrl
和 Signature
的 TextBox 控制項。 建構此介面之後,CreateUserWizard 的宣告式標記看起來應該如下所示:
<asp:CreateUserWizard ID="NewUserWizard" runat="server"
ContinueDestinationPageUrl="~/Membership/AdditionalUserInfo.aspx">
<WizardSteps>
<asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
</asp:CreateUserWizardStep>
<asp:WizardStep runat="server" ID="UserSettings" StepType="Step"
Title="Your Settings">
<p>
<b>Home Town:</b><br />
<asp:TextBox ID="HomeTown" runat="server"></asp:TextBox>
</p>
<p>
<b>Homepage URL:</b><br />
<asp:TextBox ID="HomepageUrl" Columns="40" runat="server"></asp:TextBox>
</p>
<p>
<b>Signature:</b><br />
<asp:TextBox ID="Signature" TextMode="MultiLine" Width="95%"
Rows="5" runat="server"></asp:TextBox>
</p>
</asp:WizardStep>
<asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
</asp:CompleteWizardStep>
</WizardSteps>
</asp:CreateUserWizard>
請繼續流覽此頁面,並透過瀏覽器建立新的使用者帳戶,並指定住家城市、首頁和簽章的值。 完成之後, CreateUserWizardStep
會在 Membership 架構中建立使用者帳戶,而事件處理常式會 CreatedUser
執行,這會將新的資料列新增至 UserProfiles
,但具有 、 HomepageUrl
和 Signature
的資料庫 NULL
值 HomeTown
。 永遠不會使用針對住家鎮、首頁和簽章輸入的值。 淨結果是新的使用者帳戶,其中包含 UserProfiles
尚未指定 、 HomepageUrl
和 Signature
欄位的記錄 HomeTown
。
我們需要在「您的設定」步驟之後執行程式碼,該步驟會採用使用者輸入的首頁、honepage 和簽章值,並更新適當的 UserProfiles
記錄。 每次使用者在精靈控制項中的步驟之間移動時,都會引發精靈ActiveStepChanged
的事件。 我們可以為此事件建立事件處理常式,並在「您的設定」步驟完成時更新 UserProfiles
資料表。
新增 CreateUserWizard ActiveStepChanged
事件的事件處理常式,並新增下列程式碼:
protected void NewUserWizard_ActiveStepChanged(object sender, EventArgs e)
{
// Have we JUST reached the Complete step?
if (NewUserWizard.ActiveStep.Title == "Complete")
{
WizardStep UserSettings = NewUserWizard.FindControl("UserSettings") as
WizardStep;
// Programmatically reference the TextBox controls
TextBox HomeTown = UserSettings.FindControl("HomeTown") as TextBox;
TextBox HomepageUrl = UserSettings.FindControl("HomepageUrl") as TextBox;
TextBox Signature = UserSettings.FindControl("Signature") as TextBox;
// Update the UserProfiles record for this user
// Get the UserId of the just-added user
MembershipUser newUser = Membership.GetUser(NewUserWizard.UserName);
Guid newUserId = (Guid)newUser.ProviderUserKey;
// Insert a new record into UserProfiles
string connectionString =
ConfigurationManager.ConnectionStrings["SecurityTutorialsConnectionString"].ConnectionString;
string updateSql = "UPDATE UserProfiles SET HomeTown = @HomeTown, HomepageUrl
= @HomepageUrl, Signature = @Signature WHERE UserId = @UserId";
using (SqlConnection myConnection = new SqlConnection(connectionString))
{
myConnection.Open();
SqlCommand myCommand = new SqlCommand(updateSql, myConnection);
myCommand.Parameters.AddWithValue("@HomeTown", HomeTown.Text.Trim());
myCommand.Parameters.AddWithValue("@HomepageUrl", HomepageUrl.Text.Trim());
myCommand.Parameters.AddWithValue("@Signature", Signature.Text.Trim());
myCommand.Parameters.AddWithValue("@UserId", newUserId);
myCommand.ExecuteNonQuery();
myConnection.Close();
}
}
}
上述程式碼會從判斷我們是否剛到達「完成」步驟開始。 由於「完成」步驟會在「您的設定」步驟之後立即發生,因此當訪客到達「完成」步驟時,這表示她剛完成「您的設定」步驟。
在這種情況下,我們需要以程式設計方式參考 中的 UserSettings WizardStep
TextBox 控制項。 使用 方法以程式設計方式參考 ,然後再次參考 UserSettings WizardStep
中的 TextBox, WizardStep
即可完成 FindControl
此作業。 一旦參考 TextBox,我們就可以執行 UPDATE
語句。 語句 UPDATE
的參數數目 INSERT
與事件處理常式中的 CreatedUser
語句相同,但在這裡我們使用使用者所提供的住家城市、首頁和簽章值。
有了這個事件處理常式,請流覽 EnhancedCreateUserWizard.aspx
瀏覽器頁面,並建立新的使用者帳戶,以指定住家城市、首頁和簽章的值。 建立新帳戶之後,您應該重新導向至 AdditionalUserInfo.aspx
頁面,其中會顯示剛輸入的首頁、首頁和簽章資訊。
注意
我們的網站目前有兩個頁面,訪客可以從中建立新的帳戶: CreatingUserAccounts.aspx
和 EnhancedCreateUserWizard.aspx
。 網站的網站地圖和登入頁面指向 CreatingUserAccounts.aspx
頁面,但 CreatingUserAccounts.aspx
頁面不會提示使用者輸入其主市、首頁和簽章資訊,而且不會將對應的資料列新增至 UserProfiles
。 因此,請更新 CreatingUserAccounts.aspx
頁面,使其提供這項功能,或更新要參考 EnhancedCreateUserWizard.aspx
的網站地圖和登入頁面,而不是 CreatingUserAccounts.aspx
。 如果您選擇後者選項,請務必更新 Membership
資料夾的 Web.config
檔案,以便允許匿名使用者存取 EnhancedCreateUserWizard.aspx
頁面。
摘要
在本教學課程中,我們已探討模型化資料的技術,這些資料與成員資格架構內的使用者帳戶相關。 特別是,我們查看了與使用者帳戶共用一對多關聯性的模型實體,以及共用一對一關聯性的資料。 此外,我們已瞭解如何顯示、插入和更新這項相關資訊,以及使用 SqlDataSource 控制項的一些範例,以及使用 ADO.NET 程式碼的其他範例。
本教學課程會完成我們的使用者帳戶。 從下一個教學課程開始,我們將注意角色。 在接下來的幾個教學課程中,我們將探討角色架構、如何建立新角色、如何指派角色給使用者、如何判斷使用者所屬的角色,以及如何套用角色型授權。
快樂的程式設計!
深入閱讀
如需本教學課程中所討論之主題的詳細資訊,請參閱下列資源:
- 存取和更新 ASP.NET 2.0 中的資料
- ASP.NET 2.0 精靈控制項
- 使用 ASP.NET 2.0 精靈控制項建立逐步使用者介面
- 建立自訂 DataSource 控制項參數
- 自訂 CreateUserWizard 控制項
- DetailsView 控制項快速入門
- 使用 ListView 控制項顯示資料
- 剖析 ASP.NET 2.0 中的驗證控制項
- 編輯插入和刪除資料
- ASP.NET 中的表單驗證
- 收集自訂使用者註冊資訊
- ASP.NET 2.0 中的設定檔
- asp:ListView 控制項
- 使用者設定檔快速入門
關於作者
Scott Mitchell 是多個 ASP/ASP.NET 書籍的作者,以及 4GuysFromRolla.com 的建立者,自 1998 年起就與 Microsoft Web 技術合作。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 Scott 可以透過 mitchell@4guysfromrolla.com 在 上的部落格或透過 http://ScottOnWriting.NET 其部落格來連線。
特別感謝...
本教學課程系列是由許多實用的檢閱者所檢閱。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com 。