追加のユーザー情報を格納する (VB)

作成者: Scott Mitchell

注意

この記事が作成されて以来、ASP.NET メンバーシップ プロバイダーは ASP.NET Identity に置き換えられました。 この記事の執筆時点で取り上げられたメンバーシップ プロバイダーではなく 、ASP.NET ID プラットフォームを使用するようにアプリを更新することを強くお勧めします。 ASP.NET ID には、ASP.NET メンバーシップ システムに比して、次のような多くの利点があります。

  • パフォーマンスの向上
  • 拡張性とテスト性の向上
  • OAuth、OpenID Connect、および 2 要素認証のサポート
  • クレームベースの ID のサポート
  • ASP.Net Core との相互運用性の向上

コードのダウンロード または PDF のダウンロード

このチュートリアルでは、非常に基本的なゲストブックアプリケーションを構築することで、この質問に答えます。 ここでは、データベース内のユーザー情報をモデル化するためのさまざまなオプションを確認し、このデータをメンバーシップ フレームワークによって作成されたユーザー アカウントに関連付ける方法を確認します。

はじめに

Asp。NET のメンバーシップ フレームワークは、ユーザーを管理するための柔軟なインターフェイスを提供します。 Membership API には、資格情報の検証、現在ログオンしているユーザーに関する情報の取得、新しいユーザー アカウントの作成、ユーザー アカウントの削除などのメソッドが含まれています。 Membership フレームワークの各ユーザー アカウントには、資格情報の検証と重要なユーザー アカウント関連のタスクの実行に必要なプロパティのみが含まれています。 これは、Membership フレームワークでユーザー アカウントをモデル化する クラスのMembershipUserメソッドとプロパティによって証明されます。 このクラスには、、Email、、 などのUserNameプロパティ、IsLockedOutおよび などのGetPasswordUnlockUserメソッドがあります。

多くの場合、アプリケーションでは、メンバーシップ フレームワークに含まれていない追加のユーザー情報を格納する必要があります。 たとえば、オンライン小売業者は、各ユーザーが自分の配送先住所と請求先住所、支払い情報、配送設定、連絡先電話番号を保存できるようにする必要がある場合があります。 さらに、システム内の各順序は、特定のユーザー アカウントに関連付けられます。

クラスにはMembershipUser、 や DeliveryPreferencesPastOrdersなどのPhoneNumberプロパティは含まれません。 では、アプリケーションに必要なユーザー情報を追跡し、メンバーシップ フレームワークと統合するにはどうすればよいでしょうか。 このチュートリアルでは、非常に基本的なゲストブックアプリケーションを構築することで、この質問に答えます。 ここでは、データベース内のユーザー情報をモデル化するためのさまざまなオプションを確認し、このデータをメンバーシップ フレームワークによって作成されたユーザー アカウントに関連付ける方法を確認します。 それでは作業を始めましょう。

手順 1: ゲストブック アプリケーションのデータ モデルを作成する

データベース内のユーザー情報をキャプチャし、メンバーシップ フレームワークによって作成されたユーザー アカウントに関連付けるために使用できるさまざまな手法があります。 これらの手法を説明するには、チュートリアル Web アプリケーションを拡張して、何らかのユーザー関連データをキャプチャする必要があります。 (現在、アプリケーションのデータ モデルには、 で SqlMembershipProvider必要なアプリケーション サービス テーブルのみが含まれています)。

認証されたユーザーがコメントを残すことができる非常に単純なゲストブック アプリケーションを作成しましょう。 ゲストブックのコメントを保存するだけでなく、各ユーザーが自分のホーム タウン、ホームページ、署名を保存できるようにしましょう。 指定した場合、ユーザーのホーム タウン、ホームページ、署名は、ゲストブックに残した各メッセージに表示されます。

テーブルのGuestbookComments追加

ゲストブックのコメントをキャプチャするには、 という名前GuestbookCommentsのデータベース テーブルを作成し、 などのBodyCommentIdSubjectCommentDate列を含む必要があります。 また、テーブル内の各レコードで、コメントを GuestbookComments 残したユーザーを参照する必要があります。

このテーブルをデータベースに追加するには、Visual Studio のデータベース エクスプローラーに移動し、データベースをドリルダウンしますSecurityTutorials。 [テーブル] フォルダーを右クリックし、[新しいテーブルの追加] を選択します。 これにより、新しいテーブルの列を定義できるインターフェイスが表示されます。

SecurityTutorials データベースに新しいテーブルを追加する

図 1: データベースに新しいテーブルを SecurityTutorials 追加する (フルサイズの画像を表示するをクリックします)

次に、 の列を GuestbookComments定義します。 最初に、 型uniqueidentifierの という名前CommentIdの列を追加します。 この列はゲストブック内の各コメントを一意に識別するため、 を禁止 NULL し、テーブルの主キーとしてマークします。 各 のフィールドに値CommentIdを指定するのではなく、列の既定値を に設定することで、このフィールドに対して新しいuniqueidentifierNEWID()を自動的にINSERT生成する必要があることを示すことができます。INSERT この最初のフィールドを追加し、それを主キーとしてマークし、既定値を設定すると、画面は図 2 に示すスクリーン ショットのようになります。

CommentId という名前のプライマリ列を追加する

図 2: という名前 CommentId のプライマリ列を追加する (フルサイズの画像を表示する] をクリックします)

次に、 型nvarchar(50)という名前Subjectの列と 型 という名前Bodyの列を追加し、両方のnvarchar(MAX)列で をNULL許可しないようにします。 その後、 型の という名前 CommentDate の列を追加します datetime。 を禁止 NULL し、列の CommentDate 既定値を に getdate()設定します。

残っているのは、ユーザー アカウントを各ゲストブック コメントに関連付ける列を追加することです。 1 つのオプションは、 型の という名前 UserName の列を追加することです nvarchar(256)。 これは、 以外のメンバーシップ プロバイダーを使用する場合に適した SqlMembershipProvider選択肢です。 ただし、このチュートリアル シリーズのように を SqlMembershipProvider使用する場合、 UserName テーブル内の aspnet_Users 列は一意であるとは限りません。 aspnet_Usersテーブルの主キーは でUserId、型uniqueidentifierは です。 そのため、テーブルには GuestbookCommentsuniqueidentifier (値を許可しない) という名前UserIdの列がNULL必要です。 先に進み、この列を追加します。

注意

「SQL Serverチュートリアルでのメンバーシップ スキーマの作成」で説明したように、Membership フレームワークは、異なるユーザー アカウントを持つ複数の Web アプリケーションが同じユーザー ストアを共有できるように設計されています。 これは、ユーザー アカウントを異なるアプリケーションにパーティション分割することによって行われます。 また、各ユーザー名はアプリケーション内で一意であることが保証されますが、同じユーザー ストアを使用する異なるアプリケーションで同じユーザー名を使用できます。 フィールドと ApplicationId フィールドのaspnet_UsersテーブルUserNameには複合UNIQUE制約がありますが、フィールドだけのUserName制約はありません。 したがって、aspnet_Users テーブルに同じ UserName 値を持つ 2 つ以上のレコードが含まれる可能性があります。 ただし、テーブルUserIdUNIQUEフィールドには制約aspnet_Usersがあります (主キーであるため)。 制約がないとUNIQUE、 テーブルと aspnet_Users テーブルの間に外部キー制約を確立できないため、制約はGuestbookComments重要です。

列を追加したら UserId 、ツール バーの [保存] アイコンをクリックしてテーブルを保存します。 新しいテーブルに という名前を付けます GuestbookComments

テーブルに関する最後の問題が GuestbookComments 1 つあり、列と列の間に外部キー制約を作成するGuestbookComments.UserIdaspnet_Users.UserId必要があります。 これを実現するには、ツール バーの [リレーションシップ] アイコンをクリックして、[外部キーリレーションシップ] ダイアログ ボックスを起動します。 (または、[テーブル Designer] メニューに移動し、[リレーションシップ] を選択して、このダイアログ ボックスを起動することもできます)。

[外部キーリレーションシップ] ダイアログ ボックスの左下隅にある [追加] ボタンをクリックします。 これにより、新しい外部キー制約が追加されますが、リレーションシップに関与するテーブルを定義する必要があります。

[外部キーリレーションシップ] ダイアログ ボックスを使用してテーブルの外部キー制約を管理する

図 3: [外部キーリレーションシップ] ダイアログ ボックスを使用してテーブルの外部キー制約を管理する (フルサイズの画像を表示する をクリックします)

次に、右側の [テーブルと列の仕様] 行の省略記号アイコンをクリックします。 これにより、[テーブルと列] ダイアログ ボックスが起動し、主キー テーブルと列、およびテーブルの外部キー列を GuestbookComments 指定できます。 特に、主キー テーブルと列として と UserId を選択しUserId、テーブルからGuestbookComments外部キー列として を選択aspnet_Usersします (図 4 を参照)。 主キー テーブルと外部キー テーブルと列を定義したら、[OK] をクリックして [外部キーリレーションシップ] ダイアログ ボックスに戻ります。

aspnet_Usersテーブルと GuesbookComments テーブルの間に外部キー制約を確立する

図 4: テーブルと GuesbookComments テーブルの間に外部キー制約をaspnet_Users設定する (フルサイズの画像を表示する をクリックします)

この時点で、外部キー制約が確立されました。 この制約が存在すると、存在しないユーザー アカウントを参照するゲストブック エントリが存在しないことを保証することで、2 つのテーブル間の リレーショナル整合性 が確保されます。 既定では、外部キー制約では、対応する子レコードがある場合、親レコードの削除は禁止されます。 つまり、ユーザーが 1 つ以上のゲストブック コメントを作成し、そのユーザー アカウントを削除しようとすると、ゲストブックのコメントが最初に削除されない限り、削除は失敗します。

外部キー制約は、親レコードが削除されたときに関連付けられている子レコードを自動的に削除するように構成できます。 つまり、ユーザー アカウントが削除されたときにユーザーのゲストブック エントリが自動的に削除されるように、この外部キー制約を設定できます。 これを実現するには、"INSERT and UPDATE の仕様" セクションを展開し、"ルールの削除" プロパティを Cascade に設定します。

外部キー制約を連鎖削除に構成する

図 5: 削除を連鎖するように外部キー制約を構成する (フルサイズの画像を表示する をクリックします)

外部キー制約を保存するには、[閉じる] ボタンをクリックして外部キーリレーションシップから終了します。 次に、ツール バーの [保存] アイコンをクリックして、テーブルとこのリレーションシップを保存します。

ユーザーのホーム タウン、ホームページ、署名の保存

この表は GuestbookComments 、ユーザー アカウントと一対多リレーションシップを共有する情報を格納する方法を示しています。 各ユーザー アカウントには任意の数のコメントが関連付けられている可能性があるため、このリレーションシップは、各コメントを特定のユーザーにリンクする列を含むコメントのセットを保持するテーブルを作成することによってモデル化されます。 をSqlMembershipProvider使用する場合、このリンクは、 型uniqueidentifierという名前UserIdの列と、この列と の間に外部キー制約を作成することによって最適にaspnet_Users.UserId確立されます。

ここでは、ユーザーのホーム タウン、ホームページ、署名を格納するために、各ユーザー アカウントに 3 つの列を関連付ける必要があります。これは、ゲストブックのコメントに表示されます。 これを行うには、さまざまな方法があります。

  • に新しい列を追加するaspnet_Usersまたはaspnet_Membershipテーブル。 このアプローチは によって SqlMembershipProvider使用されるスキーマを変更するため、お勧めしません。 この決定は、道を下ってあなたを悩ませるために戻ってくるかもしれません。 たとえば、将来のバージョンの ASP.NET で別 SqlMembershipProvider のスキーマが使用されている場合はどうなりますか。 Microsoft には、ASP.NET 2.0 SqlMembershipProvider データを新しいスキーマに移行するためのツールが含まれている場合がありますが、ASP.NET 2.0 SqlMembershipProvider スキーマを変更した場合、そのような変換が不可能な場合があります。

  • ASP を使用します。NET のプロファイル フレームワーク。ホーム タウン、ホームページ、署名のプロファイル プロパティを定義します。 ASP.NET には、追加のユーザー固有のデータを格納するように設計されたプロファイル フレームワークが含まれています。 メンバーシップ フレームワークと同様に、プロファイル フレームワークはプロバイダー モデルの上に構築されます。 .NET FrameworkSqlProfileProviderには、SQL Server データベースにプロファイル データを格納する が付属しています。 実際、このデータベースには、() によってSqlProfileProvideraspnet_Profile使用されるテーブルが既に含まれています。これは、SQL Serverチュートリアルのメンバーシップ スキーマの作成にアプリケーション サービスを追加したときに追加されました。
    プロファイル フレームワークのメインの利点は、開発者が でプロファイル プロパティを定義できる点です。基になるデータ ストアとの間でWeb.configプロファイル データをシリアル化するためのコードを記述する必要はありません。 つまり、プロファイル プロパティのセットを定義し、コードで操作することは非常に簡単です。 ただし、バージョン管理に関してはプロファイル システムが必要な部分が多いので、後で新しいユーザー固有のプロパティを追加する必要があるアプリケーションや、既存のプロパティを削除または変更する必要があるアプリケーションがある場合は、プロファイル フレームワークが最適なオプションではない可能性があります。 さらに、プロファイル プロパティは SqlProfileProvider 高度に非正規化された方法で格納されるため、プロファイル データに対して直接クエリを実行することは不可能になります (たとえば、ニューヨークのホーム タウンを持つユーザーの数など)。
    プロファイル フレームワークの詳細については、このチュートリアルの最後にある「さらに読む」セクションを参照してください。

  • データベース内の新しいテーブルにこれら 3 つの列を追加し、このテーブルとaspnet_Users この方法では、プロファイル フレームワークよりも少し多くの作業が必要ですが、データベースで追加のユーザー プロパティをモデル化する方法に最大限の柔軟性が提供されます。 これは、このチュートリアルで使用するオプションです。

という名前 UserProfiles の新しいテーブルを作成して、各ユーザーのホーム タウン、ホームページ、署名を保存します。 [データベース エクスプローラー] ウィンドウで [テーブル] フォルダーを右クリックし、新しいテーブルを作成することを選択します。 最初の列 UserId に名前を付け、その型を に uniqueidentifier設定します。 値を禁止 NULL し、列を主キーとしてマークします。 次に、 型の というHomeTown名前の列を追加します。型nvarchar(50)nvarchar(100)は 。 HomepageUrl 型は nvarchar(500)Signature です。 これら 3 つの列はそれぞれ、値を NULL 受け取ることができます。

UserProfiles テーブルを作成する

図 6: テーブルを作成する UserProfiles (クリックするとフルサイズの画像が表示されます)

テーブルを保存し、 という名前を付けます UserProfiles。 最後に、テーブルUserIdのフィールドとフィールドの間にUserProfiles外部キー制約をaspnet_Users.UserId設定します。 テーブルと aspnet_Users テーブルの間の外部キー制約と同様にGuestbookComments、この制約は連鎖削除されます。 のUserIdUserProfilesフィールドは主キーであるため、これにより、各ユーザー アカウントのテーブルにUserProfiles複数のレコードが存在することが保証されます。 この種類のリレーションシップは、一対一と呼ばれます。

データ モデルが作成されたので、それを使用する準備ができました。 手順 2 と 3 では、現在ログオンしているユーザーがホーム タウン、ホームページ、署名情報を表示および編集する方法について説明します。 手順 4 では、認証されたユーザーがゲストブックに新しいコメントを送信し、既存のコメントを表示するためのインターフェイスを作成します。

手順 2: ユーザーのホーム タウン、ホームページ、署名を表示する

現在ログオンしているユーザーが自分のホーム タウン、ホームページ、署名情報を表示および編集できるようにするには、さまざまな方法があります。 TextBox コントロールと Label コントロールを使用してユーザー インターフェイスを手動で作成することも、DetailsView コントロールなどのデータ Web コントロールのいずれかを使用することもできます。 データベースSELECTUPDATEステートメントを実行するために、ページの分離コード クラスに ADO.NET コードを記述するか、または SqlDataSource で宣言型アプローチを採用することもできます。 アプリケーションには階層化されたアーキテクチャが含まれているのが理想的です。このアーキテクチャは、ページの分離コード クラスからプログラムで呼び出すか、ObjectDataSource コントロールを介して宣言によって呼び出すことができます。

このチュートリアル シリーズではフォーム認証、承認、ユーザー アカウント、ロールに焦点を当てているため、これらのさまざまなデータ アクセス オプションや、ASP.NET ページから直接 SQL ステートメントを実行するよりも階層型アーキテクチャが優先される理由については詳しく説明しません。 最も簡単で簡単なオプションである DetailsView と SqlDataSource を使用して説明しますが、説明されている概念は、代替の Web コントロールとデータ アクセス ロジックに確実に適用できます。 ASP.NET でのデータの操作の詳細については、「ASP.NET 2.0 でのデータの操作 」チュートリアル シリーズを参照してください。

フォルダー内のページをMembershipAdditionalUserInfo.aspx開き、DetailsView コントロールをページに追加し、ID プロパティを にUserProfile設定し、そのプロパティとHeightプロパティをWidthクリアします。 DetailsView のスマート タグを展開し、新しいデータ ソース コントロールにバインドすることを選択します。 これにより、DataSource 構成ウィザードが起動します (図 7 を参照)。 最初の手順では、データ ソースの種類を指定するように求められます。 データベースに直接接続SecurityTutorialsするため、[ データベース] アイコンを選択し、 を としてUserProfileDataSource指定IDします。

UserProfileDataSource という名前の新しい SqlDataSource コントロールを追加する

図 7: 名前付きの UserProfileDataSource 新しい SqlDataSource コントロールを追加する (フルサイズの画像を表示する をクリックします)

次の画面では、データベースを使用するように求められます。 データベースの 接続文字列 は既にWeb.configSecurityTutorials定義されています。 この接続文字列名 – SecurityTutorialsConnectionString は、ドロップダウン リストに含まれている必要があります。 このオプションを選択し、[次へ] をクリックします。

Drop-Down リストから [SecurityTutorialsConnectionString] を選択します

図 8: Drop-Down リストから選択 SecurityTutorialsConnectionString する (フルサイズの画像を表示する をクリックします)

後続の画面では、クエリを実行するテーブルと列を指定するように求められます。 UserProfilesドロップダウン リストからテーブルを選択し、すべての列をチェックします。

UserProfiles テーブルからすべての列を取り戻す

図 9: テーブルから UserProfiles すべての列を取り戻す (フルサイズの画像を表示する をクリックします)

図 9 の 現在のクエリ は、 のすべての UserProfilesレコードを返しますが、現在ログオンしているユーザーのレコードにのみ関心があります。 句を WHERE 追加するには、ボタンを WHERE クリックして [句の追加 WHERE ] ダイアログ ボックスを表示します (図 10 を参照)。 ここでは、フィルターを適用する列、演算子、フィルター パラメーターのソースを選択できます。 列として を選択し、演算子として "=" を選択 UserId します。

残念ながら、現在ログオンしているユーザー UserId の値を返す組み込みのパラメーター ソースはありません。 この値をプログラムで取得する必要があります。 そのため、[ソース] ドロップダウン リストを [なし] に設定し、[追加] ボタンをクリックしてパラメーターを追加し、[OK] をクリックします。

UserId 列にフィルター パラメーターを追加する

図 10: 列にフィルター パラメーターを追加する UserId (フルサイズの画像を表示する をクリックします)

[OK] をクリックすると、図 9 に示す画面に戻ります。 ただし、今回は、画面の下部にある SQL クエリに 句を WHERE 含める必要があります。 [次へ] をクリックして、[クエリのテスト] 画面に移動します。 ここでは、クエリを実行して結果を確認できます。 [完了] をクリックしてウィザードを終了します。

DataSource 構成ウィザードが完了すると、ウィザードで指定された設定に基づいて SqlDataSource コントロールが作成されます。 さらに、SqlDataSource SelectCommandの によって返される各列の DetailsView に BoundFields を手動で追加します。 ユーザーはこの値を UserId 知る必要がないため、DetailsView にフィールドを表示する必要はありません。 このフィールドは、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 Sub UserProfileDataSource_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceSelectingEventArgs) Handles UserProfileDataSource.Selecting
     ' Get a reference to the currently logged on user
     Dim currentUser As MembershipUser = Membership.GetUser()

     ' Determine the currently logged on user's UserId value
     Dim currentUserId As Guid = CType(currentUser.ProviderUserKey, Guid)

     ' Assign the currently logged on user's UserId to the @UserId parameter
     e.Command.Parameters("@UserId").Value = currentUserId
End Sub

上記のコードは、まず、 クラスGetUserの メソッドを呼び出して、現在ログオンしているユーザーへの参照をMembership取得します。 これにより、 ProviderUserKey プロパティに がMembershipUser含まれる オブジェクトが返されますUserId。 その UserId 後、値は SqlDataSource @UserId のパラメーターに割り当てられます。

注意

メソッドは Membership.GetUser() 、現在ログオンしているユーザーに関する情報を返します。 匿名ユーザーがページにアクセスしている場合は、 の Nothing値が返されます。 このような場合、 プロパティを NullReferenceException 読み取ろうとすると、次のコード行で が ProviderUserKey 発生します。 もちろん、認証されたユーザーのみがこのフォルダー内の AdditionalUserInfo.aspx ASP.NET リソースにアクセスできるように、前のチュートリアルで URL 承認を構成したため、ページに Nothing が返されることを心配する必要Membership.GetUser()はありません。 匿名アクセスが許可されているページで現在ログオンしているユーザーに関する情報にアクセスする必要がある場合は、プロパティを参照する前にMembershipUser、メソッドから返されたオブジェクトが Nothing ではないことをGetUser()チェックしてください。

ブラウザーを使用してページに AdditionalUserInfo.aspx アクセスすると、テーブルに行を追加していないため、空白のページが UserProfiles 表示されます。 手順 6 では、CreateUserWizard コントロールをカスタマイズして、新しいユーザー アカウントの作成時にテーブルに新しい行を自動的に追加する UserProfiles 方法について説明します。 ただし、ここではテーブルに手動でレコードを作成する必要があります。

Visual Studio の [データベース] エクスプローラーに移動し、[テーブル] フォルダーを展開します。 テーブルを右クリックし、[テーブル データの aspnet_Users 表示] を選択してテーブル内のレコードを表示します。テーブルに対 UserProfiles して同じことを行います。 図 11 は、垂直方向に並べて表示された場合のこれらの結果を示しています。 私のデータベースには現在 aspnet_Users 、Bruce、Fred、Titoのレコードがありますが、テーブルに UserProfiles レコードはありません。

aspnet_Usersテーブルと UserProfiles テーブルの内容が表示されます

図 11: テーブルと UserProfiles テーブルのaspnet_Users内容が表示されます (クリックするとフルサイズの画像が表示されます)

、、および フィールドの値をUserProfiles手動で入力して、テーブルに新しいレコードをSignatureHomeTownHomepageUrl追加します。 新しいUserProfilesレコードで有効なUserId値を取得する最も簡単な方法は、テーブル内の特定のユーザー アカウントからフィールドをaspnet_Users選択UserIdし、 のフィールドUserProfilesUserIdコピーして貼り付けることです。 図 12 は、Bruce に UserProfiles 新しいレコードが追加された後のテーブルを示しています。

Bruce の UserProfiles にレコードが追加されました

図 12: Bruce の にレコードが追加 UserProfiles されました (フルサイズの画像を表示する をクリックします)

に戻り、 AdditionalUserInfo.aspx pageBruce としてログインします。 図 13 に示すように、Bruce の設定が表示されます。

現在アクセスしているユーザーに自分の設定が表示される

図 13: 現在アクセスしているユーザーの設定が表示されている (フルサイズの画像を表示する をクリックします)

注意

次に進み、各メンバーシップ ユーザーのテーブルにレコードを UserProfiles 手動で追加します。 手順 6 では、CreateUserWizard コントロールをカスタマイズして、新しいユーザー アカウントの作成時にテーブルに新しい行を自動的に追加する UserProfiles 方法について説明します。

手順 3: ユーザーがホーム タウン、ホームページ、署名を編集できるようにする

この時点で、現在ログインしているユーザーはホーム タウン、ホームページ、署名の設定を表示できますが、まだ変更することはできません。 データを編集できるように DetailsView コントロールを更新しましょう。

最初に、実行するステートメントとそれに対応するパラメーターを指定してUPDATE、SqlDataSource の を追加UpdateCommandする必要があります。 SqlDataSource を選択し、プロパティ ウィンドウから UpdateQuery プロパティの横にある省略記号をクリックして、[コマンドとパラメーターのエディター] ダイアログ ボックスを表示します。 テキスト ボックスに次 UPDATE のステートメントを入力します。

UPDATE UserProfiles SET
     HomeTown = @HomeTown,
     HomepageUrl = @HomepageUrl,
     Signature = @Signature
WHERE UserId = @UserId

次に、[パラメーターの更新] ボタンをクリックします。これにより、 ステートメント内の各パラメーターのパラメーターが SqlDataSource コントロールの UpdateParameters コレクションに UPDATE 作成されます。 すべてのパラメーターのソースを [なし] に設定したまま、[OK] ボタンをクリックしてダイアログ ボックスを完了します。

SqlDataSource の UpdateCommand と UpdateParameters を指定する

図 14: SqlDataSource の と UpdateParameters を指定します (フルサイズのUpdateCommand画像を表示するには、ここをクリックします)

SqlDataSource コントロールに追加されたため、DetailsView コントロールで編集をサポートできるようになりました。 DetailsView のスマート タグから、[編集を有効にする] チェック ボックスをチェックします。 これにより、プロパティが True に設定された CommandField がコントロールの Fields コレクション ShowEditButton に追加されます。 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アクセスすると、ユーザーの設定が編集可能なインターフェイスに表示されます。

DetailsView は編集可能なインターフェイスをレンダリングします

図 15: DetailsView は編集可能なインターフェイスをレンダリングします (フルサイズの画像を表示するには、ここをクリックします)

値を変更し、[更新] ボタンをクリックしてみてください。 何も起こっていないかのように見えます。 ポストバックがあり、値はデータベースに保存されますが、保存が発生したという視覚的なフィードバックはありません。

これを解決するには、Visual Studio に戻り、DetailsView の上にラベル コントロールを追加します。 を IDSettingsUpdatedMessage設定し、その 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 Sub UserProfile_ItemUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewUpdatedEventArgs) Handles UserProfile.ItemUpdated
     SettingsUpdatedMessage.Visible = True
End Sub

ブラウザーからページに AdditionalUserInfo.aspx 戻り、データを更新します。 今回は、役に立つステータス メッセージが表示されます。

設定が更新されると短いメッセージが表示される

図 16: 設定が更新されたときに短いメッセージが表示される (フルサイズの画像を表示する をクリックします)

注意

DetailsView コントロールの編集インターフェイスを使用すると、多くの処理が必要になります。 標準サイズのテキスト ボックスを使用しますが、[署名] フィールドはおそらく複数行のテキスト ボックスである必要があります。 RegularExpressionValidator を使用して、ホームページの URL が入力された場合は、"http://" または "https://" で始まっていることを確認する必要があります。 さらに、DetailsView コントロールのプロパティは DefaultModeEdit設定されているため、[キャンセル] ボタンは何も行いません。 削除するか、クリックすると、ユーザーを他のページ (など ~/Default.aspx) にリダイレクトする必要があります。 これらの機能強化は、読者の演習として残しておきます。

現在、この Web サイトではページへのリンクは AdditionalUserInfo.aspx 提供されていません。 アクセスする唯一の方法は、ブラウザーのアドレス バーにページの URL を直接入力することです。 マスター ページでこのページへのリンクを Site.master 追加しましょう。

マスター ページの ContentPlaceHolder に LoginView Web コントロール LoginContent が含まれており、認証された訪問者と匿名の訪問者に対して異なるマークアップが表示されることを思い出してください。 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 ページでは、認証されたユーザーがゲストブックを表示し、コメントを残すことができます。 新しいゲストブックコメントを追加するインターフェイスの作成から始めましょう。

Visual Studio でページを Guestbook.aspx 開き、新しいコメントの件名と本文用の 2 つの TextBox コントロールで構成されるユーザー インターフェイスを構築します。 最初の TextBox コントロールの ID プロパティを に Subject 設定し、その Columns プロパティを 40 に設定し、second の ID を に Body、その TextMode を に MultiLine、プロパティ WidthRows プロパティをそれぞれ "95%" と 8 に設定します。 ユーザー インターフェイスを完了するには、 という名前 PostCommentButton の Button Web コントロールを追加し、その Text プロパティを "コメントの投稿" に設定します。

各ゲストブック コメントには件名と本文が必要であるため、各 TextBoxes に RequiredFieldValidator を追加します。 これらのコントロールの プロパティを ValidationGroup "EnterComment" に設定します。同様に、コントロールの ValidationGroup プロパティを "EnterComment" に設定PostCommentButtonします。 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挿入することです。 これは、さまざまな方法で実現できます。ボタンのClickイベント ハンドラーでコード ADO.NET 記述できます。SqlDataSource コントロールをページに追加し、その InsertCommandを構成し、イベント ハンドラーからClickメソッドをInsert呼び出すことができます。または、新しいゲストブック コメントを挿入する中間層を構築し、イベント ハンドラーからこの機能をClick呼び出すことができます。 手順 3 で SqlDataSource の使用を見たので、ここで ADO.NET コードを使用しましょう。

注意

Microsoft SQL Server データベースからプログラムでデータにアクセスするために使用される ADO.NET クラスは、 名前空間にありますSystem.Data.SqlClient。 この名前空間は、ページの分離コード クラス (つまり) Imports System.Data.SqlClientにインポートする必要がある場合があります。

の イベントのイベント ハンドラーをPostCommentButtonClick作成し、次のコードを追加します。

Protected Sub PostCommentButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles PostCommentButton.Click
     If Not Page.IsValid Then Exit Sub

     ' Determine the currently logged on user's UserId
     Dim currentUser As MembershipUser = Membership.GetUser()
     Dim currentUserId As Guid = CType(currentUser.ProviderUserKey, Guid)

     ' Insert a new record into GuestbookComments
     Dim connectionString As String = 
          ConfigurationManager.ConnectionStrings("SecurityTutorialsConnectionString").ConnectionString
     Dim insertSql As String = "INSERT INTO GuestbookComments(Subject, Body, UserId)
          VALUES(@Subject, @Body, @UserId)"

     Using myConnection As New SqlConnection(connectionString)

          myConnection.Open()
          Dim myCommand As 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()
     End Using

     ' "Reset" the Subject and Body TextBoxes

     Subject.Text = String.Empty
     Body.Text = String.Empty
End Sub

イベント ハンドラーは Click 、ユーザーが指定したデータが有効であることを確認することから始めます。 そうでない場合、イベント ハンドラーはレコードを挿入する前に終了します。 指定されたデータが有効であると仮定すると、現在ログオンしているユーザーの UserId 値が取得され、ローカル変数に currentUserId 格納されます。 にレコードGuestbookCommentsを挿入するときに値をUserId指定する必要があるため、この値が必要です。

その後、データベースの接続文字列SecurityTutorialsが からWeb.config取得され、INSERTSQL ステートメントが指定されます。 SqlConnectionその後、オブジェクトが作成されて開かれます。 次に SqlCommand 、オブジェクトが構築され、クエリで使用されるパラメーターの INSERT 値が割り当てられます。 INSERTステートメントが実行され、接続が閉じられます。 イベント ハンドラーの最後に、 Subject プロパティと Body TextBoxes プロパティ Text がクリアされるため、ユーザーの値はポストバック全体で保持されません。

先に進み、ブラウザーでこのページをテストします。 このページはフォルダー内にありますので Membership 、匿名の訪問者はアクセスできません。 そのため、最初にログオンする必要があります (まだログオンしていない場合)。 と Body TextBoxes に値をSubject入力し、ボタンをPostCommentButtonクリックします。 これにより、新しいレコードが に GuestbookComments追加されます。 ポストバックでは、指定した件名と本文が TextBoxes からワイプされます。

ボタンをクリックすると、 PostCommentButton コメントがゲストブックに追加されたという視覚的なフィードバックはありません。 既存のゲストブックコメントを表示するには、このページを更新する必要があります。これは手順 5 で行います。 これを完了すると、追加したコメントがコメントの一覧に表示され、適切な視覚的フィードバックが提供されます。 ここでは、テーブルの内容を調べて、ゲストブックの GuestbookComments コメントが保存されたことを確認します。

図 17 は、2 つのコメントが残された後の GuestbookComments テーブルの内容を示しています。

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に名前を付け、[OK] をクリックします。 次にSecurityTutorialsConnectionString、ドロップダウン リストから接続文字列を選択し、[次へ] をクリックします。

手順 2 のこの時点で、クエリを実行するデータを指定しました。そのためには、ドロップダウン リストからテーブルを選択 UserProfiles し、返す列を選択します (図 9 を参照)。 ただし、今回は、 から GuestbookCommentsレコードだけでなく、コメント者のホーム タウン、ホームページ、署名、ユーザー名も取り戻す SQL ステートメントを作成したいと考えています。 そのため、[カスタム SQL ステートメントまたはストアド プロシージャを指定する] ラジオ ボタンを選択し、[次へ] をクリックします。

これにより、[カスタム ステートメントまたはストアド プロシージャの定義] 画面が表示されます。 [クエリ ビルダー] ボタンをクリックして、クエリをグラフィカルに作成します。 クエリ ビルダーは、クエリを実行するテーブルの指定を求めるメッセージを表示することから始まります。 、UserProfiles、および の各テーブルをGuestbookCommentsaspnet_Users選択し、[OK] をクリックします。 これにより、3 つのテーブルすべてがデザイン サーフェイスに追加されます。 、UserProfiles、および aspnet_Users の各テーブルにはGuestbookComments外部キー制約があるため、クエリ ビルダーはこれらのテーブルを自動的JOINに作成します。

残っているのは、返す列を指定することです。 テーブルから GuestbookComments 、、Bodyおよび 列をSubject選択しCommentDate、テーブルから 、HomepageUrl、および Signature 列をUserProfilesHomeTownし、 からaspnet_Usersを返しますUserName。 また、クエリのSELECT最後に "ORDER BY CommentDate DESC" を追加して、最新の投稿が最初に返されるようにします。 これらの選択を行った後、クエリ ビルダー インターフェイスは図 18 のスクリーン ショットのようになります。

GuestbookComments、UserProfiles、および aspnet_Users テーブルの構築されたクエリ JOIN

図 18: 構築されたクエリ JOINGuestbookCommentsUserProfiles、および aspnet_Users テーブル (フルサイズの画像を表示する をクリックします)

[OK] をクリックして [クエリ ビルダー] ウィンドウを閉じ、[カスタム ステートメントまたはストアド プロシージャの定義] 画面に戻ります。 [次へ] をクリックして [クエリのテスト] 画面に進み、[クエリのテスト] ボタンをクリックしてクエリ結果を表示できます。 準備ができたら、[完了] をクリックしてデータ ソースの構成ウィザードを完了します。

手順 2 でデータ ソースの構成ウィザードを完了すると、関連付けられている DetailsView コントロールの Fields コレクションが更新され、 によって返される各列の BoundField が SelectCommand含まれます。 ただし、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結果のマークアップは、 の コントロールにLayoutTemplateitemPlaceholder配置されます。 にitemPlaceholderLayoutTemplate加えて、 には DataPager コントロールが含まれており、ListView は 1 ページあたり 10 個のゲストブック コメント (既定) のみを表示するように制限され、ページング インターフェイスがレンダリングされます。

My では ItemTemplate 、各ゲストブック コメントの件名が、件名 <h4> の下に本文が配置された要素に表示されます。 本文の表示に使用される構文は、databinding ステートメントによって返されるデータを Eval("Body") 受け取り、それを文字列に変換し、改行を 要素に <br /> 置き換えます。 HTML では空白文字が無視されるため、コメントの送信時に入力された改行を表示するには、この変換が必要です。 ユーザーの署名は、本文の下に斜体で表示され、その後にユーザーのホーム タウン、ホーム ページへのリンク、コメントが作成された日時、コメントを残したユーザーのユーザー名が表示されます。

ブラウザーを使用してページを表示するには、少し時間を取ります。 手順 5 でゲストブックに追加したコメントがここに表示されます。

Guestbook.aspxゲストブックのコメントが表示されるようになりました

図 19: Guestbook.aspx ゲストブックのコメントが表示されるようになりました (クリックするとフルサイズの画像が表示されます)

ゲストブックに新しいコメントを追加してみてください。 ボタンを PostCommentButton クリックすると、ページはポストバックされ、コメントはデータベースに追加されますが、ListView コントロールは更新されず、新しいコメントが表示されます。 これは、次のいずれかの方法で修正できます。

  • 新しいコメントをデータベースに PostCommentButton 挿入した後に ListView コントロールの メソッドを呼び出すようにボタン ClickDataBind() イベント ハンドラーを更新する、または
  • ListView コントロールの プロパティを EnableViewState に設定します False。 この方法は、コントロールのビュー ステートを無効にすることで、すべてのポストバックの基になるデータに再バインドする必要があるために機能します。

このチュートリアルからダウンロードできるチュートリアル Web サイトは、両方の手法を示しています。 ListView コントロールの EnableViewState プロパティ False と、プログラムによって ListView にデータを再バインドするために必要なコードは、イベント ハンドラーに Click 存在しますが、コメントアウトされます。

注意

現在、 AdditionalUserInfo.aspx このページでは、ユーザーがホーム タウン、ホームページ、署名の設定を表示および編集できます。 ログインしているユーザーのゲストブックのコメントを表示するように更新 AdditionalUserInfo.aspx すると便利な場合があります。 つまり、ユーザーは、自分の情報を調べて変更するだけでなく、ページにアクセス AdditionalUserInfo.aspx して、過去に行ったゲストブックのコメントを確認できます。 私はこれを興味のある読者のための演習として残します。

手順 6: CreateUserWizard コントロールをカスタマイズして、ホーム タウン、ホームページ、署名のインターフェイスを含める

ページで使用されるクエリではSELECT、 をINNER JOINGuestbook.aspx使用して、、UserProfiles、および aspnet_Users テーブルの間で関連レコードをGuestbookComments結合します。 にレコードUserProfilesがないユーザーがゲストブック コメントを作成した場合、 と に一致するレコードがある場合にのみレコードが返GuestbookCommentsされるためINNER JOIN、コメントは ListView にUserProfilesaspnet_Users表示されません。 手順 3 で説明したように、ユーザーがレコードを持っていない場合、ページで UserProfiles 設定を AdditionalUserInfo.aspx 表示または編集することはできません。

言うまでもなく、設計上の決定により、メンバーシップ システム内のすべてのユーザー アカウントがテーブル内に一致するレコードを UserProfiles 持つことが重要です。 必要なのは、CreateUserWizard を使用して新しいメンバーシップ ユーザー アカウントが作成されるたびに、対応するレコードを に追加 UserProfiles することです。

「ユーザー アカウントの作成」チュートリアルで説明したように、新しいメンバーシップ ユーザー アカウントが作成された後、CreateUserWizard コントロールによってイベントがCreatedUser発生します。 このイベントのイベント ハンドラーを作成し、作成したユーザーの UserId を取得してから、および Signature 列のUserProfiles既定値を使用してレコードをHomeTownHomepageUrlテーブルに挿入できます。 さらに、追加の TextBox を含むように CreateUserWizard コントロールのインターフェイスをカスタマイズすることで、ユーザーにこれらの値の入力を求めることができます。

まず、イベント ハンドラーのテーブルに新しい行を UserProfiles 既定値で追加する方法を CreatedUser 見てみましょう。 その後、CreateUserWizard コントロールのユーザー インターフェイスをカスタマイズして、新しいユーザーのホーム タウン、ホーム ページ、署名を収集するための追加のフォーム フィールドを含める方法について説明します。

既定の行の追加UserProfiles

ユーザー アカウントの作成に関するチュートリアルでは、フォルダー内のページに CreatingUserAccounts.aspx CreateUserWizard コントロールをMembership追加しました。 CreateUserWizard コントロールがユーザー アカウントの作成時にテーブルにレコードを UserProfiles 追加するには、CreateUserWizard コントロールの機能を更新する必要があります。 これらの変更をページに CreatingUserAccounts.aspx 加えるのではなく、新しい CreateUserWizard コントロールをページに EnhancedCreateUserWizard.aspx 追加し、そこでこのチュートリアルの変更を加えてみましょう。

Visual Studio でページを EnhancedCreateUserWizard.aspx 開き、CreateUserWizard コントロールをツールボックスからページにドラッグします。 CreateUserWizard コントロールの ID プロパティを に設定します NewUserWizard「ユーザー アカウントの作成」チュートリアルで説明したように、CreateUserWizard の既定のユーザー インターフェイスは、訪問者に必要な情報を求めるメッセージを表示します。 この情報が提供されると、コントロールは内部的にメンバーシップ フレームワークに新しいユーザー アカウントを作成します。コードを 1 行記述する必要はありません。

CreateUserWizard コントロールは、ワークフロー中に多数のイベントを発生させます。 訪問者が要求情報を提供し、フォームを送信すると、CreateUserWizard コントロールは最初にイベントを CreatingUser 発生させます。 作成プロセス中に問題が発生すると CreateUserError 、イベント が発生します。ただし、ユーザーが正常に作成されると、 CreatedUser イベント が発生します。 ユーザー アカウントの作成に関するチュートリアルでは、 イベントのCreatingUserイベント ハンドラーを作成して、指定されたユーザー名に先頭または末尾のスペースが含まれていないことを確認し、ユーザー名がパスワードのどこにも表示されないようにしました。

作成したばかりのユーザーのテーブルに行を UserProfiles 追加するには、イベントのイベント ハンドラーを作成する CreatedUser 必要があります。 イベントが CreatedUser 発生した時点で、ユーザー アカウントは既にメンバーシップ フレームワークに作成されているため、アカウントの UserId 値を取得できます。

のイベントのイベント ハンドラーを NewUserWizard作成し、次の CreatedUser コードを追加します。

Protected Sub NewUserWizard_CreatedUser(ByVal sender As Object, ByVal e As System.EventArgs) Handles NewUserWizard.CreatedUser
     ' Get the UserId of the just-added user
     Dim newUser As MembershipUser = Membership.GetUser(NewUserWizard.UserName)
     Dim newUserId As Guid = CType(newUser.ProviderUserKey, Guid)

     ' Insert a new record into UserProfiles
     Dim connectionString As String = 

          ConfigurationManager.ConnectionStrings("SecurityTutorialsConnectionString").ConnectionString
     Dim insertSql As String = "INSERT INTO UserProfiles(UserId, HomeTown, HomepageUrl,
          Signature) VALUES(@UserId, @HomeTown, @HomepageUrl, @Signature)"

     Using myConnection As New SqlConnection(connectionString)
          myConnection.Open()
          Dim myCommand As 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()
     End Using
End Sub

上記のコードは、追加したばかりのユーザー アカウントの UserId を取得することです。 これを行うには、 メソッドを使用して特定の Membership.GetUser(username) ユーザーに関する情報を返し、 プロパティを ProviderUserKey 使用して UserId を取得します。 CreateUserWizard コントロールでユーザーが入力したユーザー名は、そのUserNameプロパティを使用して使用できます。

次に、接続文字列が からWeb.config取得され、 ステートメントがINSERT指定されます。 必要な ADO.NET オブジェクトがインスタンス化され、コマンドが実行されます。 このコードでは、および @Signature の各パラメーターに@HomepageUrl@HomeTownインスタンスを割り当てますDBNull。このパラメーターは、、HomepageUrl、および Signature フィールドのデータベースNULL値をHomeTown挿入する効果があります。

ブラウザーからページに EnhancedCreateUserWizard.aspx アクセスし、新しいユーザー アカウントを作成します。 その後、Visual Studio に戻り、 テーブルと UserProfiles テーブルの内容をaspnet_Users調べます (図 12 で取り上げました)。 の新しいユーザー アカウントaspnet_Usersと、対応するUserProfiles行 (、、HomepageUrlおよび SignatureHomeTown値を含むNULL) が表示されます。

新しいユーザー アカウントと UserProfiles レコードが追加されました

図 20: 新しいユーザー アカウントと UserProfiles レコードが追加されました (クリックするとフルサイズの画像が表示されます)

訪問者が新しいアカウント情報を入力し、[ユーザーの作成] ボタンをクリックすると、ユーザー アカウントが作成され、テーブルに行が UserProfiles 追加されます。 次に、CreateUserWizard に が CompleteWizardStep表示され、成功メッセージと [続行] ボタンが表示されます。 [続行] ボタンをクリックするとポストバックが発生しますが、アクションは実行されません。ユーザーはページ上 EnhancedCreateUserWizard.aspx でスタックしたままです。

CreateUserWizard コントロール ContinueDestinationPageUrl の プロパティを使用して [続行] ボタンをクリックすると、ユーザーに送信する URL を指定できます。 プロパティを ContinueDestinationPageUrl "~/Membership/AdditionalUserInfo.aspx" に設定します。 これにより、新しいユーザーは に移動 AdditionalUserInfo.aspxし、そこで設定を表示および更新できます。

CreateUserWizard のインターフェイスをカスタマイズして、新しいユーザーのホーム タウン、ホーム ページ、署名の入力を求める

CreateUserWizard コントロールの既定のインターフェイスは、ユーザー名、パスワード、電子メールなどのコア ユーザー アカウント情報のみを収集する必要がある単純なアカウント作成シナリオに十分です。 しかし、アカウントの作成時に訪問者にホームタウン、ホームページ、署名の入力を求めたい場合はどうでしょうか。 サインアップ時に追加情報を収集するように CreateUserWizard コントロールのインターフェイスをカスタマイズできます。この情報は、イベント ハンドラーで CreatedUser 使用して、基になるデータベースに追加のレコードを挿入する場合があります。

CreateUserWizard コントロールは、ページ開発者が一連の順序付き を定義できるようにするコントロールである、ASP.NET ウィザード コントロールを拡張します WizardSteps。 ウィザード コントロールは、アクティブなステップをレンダリングし、訪問者がこれらの手順を移動できるようにするナビゲーション インターフェイスを提供します。 ウィザード コントロールは、長いタスクをいくつかの短い手順に分割するのに最適です。 ウィザード コントロールの詳細については、「 ASP.NET 2.0 ウィザード コントロールを使用したステップ バイ ステップ ユーザー インターフェイスの作成」を参照してください。

CreateUserWizard コントロールの既定のマークアップは、 と CompleteWizardStepの 2 つWizardStepsCreateUserWizardStepを定義します。

<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 コントロールのインターフェイスをカスタマイズして、追加のフォーム フィールドを含めるには、次の操作を行います。

  • 1 つ以上の新しいWizardStepを作成するは、追加のユーザー インターフェイス要素を格納します。 CreateUserWizard に新WizardStepしいを追加するには、スマート タグから [追加/削除WizardStep] リンクをクリックしてコレクション エディターをWizardStep起動します。 そこから、ウィザードの手順を追加、削除、または並べ替えることができます。 これは、このチュートリアルで使用するアプローチです。

  • を変換します。CreateUserWizardStepを編集可能にするWizardStep これにより、 が CreateUserWizardStep と一致するユーザー インターフェイスを定義する同等 WizardStep のマークアップに CreateUserWizardStep置き換えられます。 を CreateUserWizardStepWizardStep 変換することで、コントロールの位置を変更したり、この手順にユーザー インターフェイス要素を追加したりできます。 または CompleteWizardStepCreateUserWizardStep編集可能にWizardStep変換するには、コントロールのスマート タグから [ユーザー ステップの作成のカスタマイズ] または [完全なステップのカスタマイズ] リンクをクリックします。

  • 上記の 2 つのオプションを組み合わせて使用します。

注意すべき重要な点の 1 つは、CreateUserWizard コントロールが、その 内から [Create User]\(ユーザーの作成\) ボタンをクリックしたときに、ユーザー アカウントの作成プロセスを CreateUserWizardStep実行することです。 の後CreateUserWizardStepに 追加WizardStepの が存在するかどうかは関係ありません。

CreateUserWizard コントロールにカスタム WizardStep を追加して追加のユーザー入力を収集する場合は、 の前または後にカスタム WizardStepCreateUserWizardStep配置できます。 が の CreateUserWizardStep 前にある場合は、カスタム WizardStep から収集された追加のユーザー入力をイベント ハンドラーで CreatedUser 使用できます。 ただし、カスタムが表示される時点までにカスタムWizardStepが表示される場合CreateUserWizardStepは、新しいユーザー アカウントが既に作成されており、イベントが既にCreatedUser発生WizardStepしています。

図 21 は、 が の前に追加 WizardStep されたときのワークフローを CreateUserWizardStep示しています。 イベントが発生した時点CreatedUserで追加のユーザー情報が収集されるため、これらの入力を取得し、ステートメントのパラメーター値 (ではなくDBNull.Value) に使用INSERTするようにイベント ハンドラーを更新CreatedUserするだけで済みます。

CreateUserWizard ワークフロー: 追加の WizardStep が CreateUserWizardStep の前にある場合

図 21: CreateUserWizard ワークフローが の前CreateUserWizardStepに追加WizardStepされたとき (クリックするとフルサイズの画像が表示されます)

ただし、 のCreateUserWizardStepにカスタムWizardStepを配置すると、ユーザーがホーム タウン、ホームページ、または署名に入る前に、ユーザー アカウントの作成プロセスが行われます。 このような場合は、図 22 に示すように、ユーザー アカウントの作成後に、この追加情報をデータベースに挿入する必要があります。

CreateUserWizardStep の後に追加の WizardStep が来たときの CreateUserWizard ワークフロー

図 22: CreateUserWizard ワークフローの後CreateUserWizardStepに追加WizardStepが来たとき (クリックするとフルサイズの画像が表示されます)

図 22 に示すワークフローは、手順 2 が完了するまでテーブルへのレコードの UserProfiles 挿入を待機します。 ただし、手順 1 の後に訪問者がブラウザーを閉じると、ユーザー アカウントが作成された状態に達しましたが、 に UserProfilesレコードは追加されませんでした。 回避策の 1 つは、イベント ハンドラーに または の既定値を含むNULLレコードをCreatedUser挿入UserProfilesし (手順 1 の後に発生します)、手順 2 の完了後にこのレコードを更新することです。 これにより、ユーザーが途中で UserProfiles 登録プロセスを終了した場合でも、ユーザー アカウントのレコードが確実に追加されます。

このチュートリアルでは、 の後と の前CreateUserWizardStepに発生する新しい WizardStepCompleteWizardStep作成しましょう。 最初に WizardStep を設定し、構成してから、コードを見てみましょう。

CreateUserWizard コントロールのスマート タグから、[追加/削除WizardStep] を選択すると、[コレクションのエディター] ダイアログが表示WizardStepされます。 新 WizardStepしい を追加し、 を IDUserSettings設定し、その Title を "Your Settings" に、その を StepType に設定します Step。 次に、図 23 に示すように、 CreateUserWizardStep ("新しいアカウントにサインアップ") の後と ("完了") の前 CompleteWizardStep に来るように配置します。

CreateUserWizard コントロールに新しい WizardStep を追加する

図 23: CreateUserWizard コントロールに新規 WizardStep を追加する (フルサイズの画像を表示する をクリックします)

[OK] をクリックして、[コレクションのWizardStepエディター] ダイアログを閉じます。 新しい 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したときにこの手順が表示されるようにしてください。

、、および という名前HomeTownHomepageUrlの 3 つの TextBox コントロールを含む "設定" ステップ内にユーザー インターフェイスをSignature作成します。 このインターフェイスを構築すると、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 ユーザー アカウントがメンバーシップ フレームワークに作成され、イベント ハンドラーが実行されます CreatedUser 。これにより、 に UserProfiles新しい行が追加されますが、データベース NULLHomeTownは 、 HomepageUrl、および Signatureになります。 ホーム タウン、ホームページ、署名に入力された値は使用されません。 結果は、および Signature フィールドがまだ指定されていないレコードHomepageUrlHomeTownを持つUserProfiles新しいユーザー アカウントです。

ユーザーが入力したホーム タウン、honepage、署名の値を取得し、適切なレコードを更新する "設定" ステップの後にコードを実行する必要があります UserProfiles 。 ユーザーがウィザード コントロールのステップ間を移動するたびに、ウィザードの ActiveStepChanged イベント が発生します。 このイベントのイベント ハンドラーを作成し、"設定" ステップが UserProfiles 完了したらテーブルを更新できます。

CreateUserWizard のイベントのイベント ハンドラーを追加し、次の ActiveStepChanged コードを追加します。

Protected Sub NewUserWizard_ActiveStepChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles NewUserWizard.ActiveStepChanged
     ' Have we JUST reached the Complete step?
     If NewUserWizard.ActiveStep.Title = "Complete" Then
          Dim UserSettings As WizardStep = CType(NewUserWizard.FindControl("UserSettings"),WizardStep)

          ' Programmatically reference the TextBox controls
          Dim HomeTown As TextBox = CType(UserSettings.FindControl("HomeTown"), TextBox)
          Dim HomepageUrl As TextBox = CType(UserSettings.FindControl("HomepageUrl"), TextBox)
          Dim Signature As TextBox = CType(UserSettings.FindControl("Signature"), TextBox)

          ' Update the UserProfiles record for this user
          ' Get the UserId of the just-added user
          Dim newUser As MembershipUser = Membership.GetUser(NewUserWizard.UserName)
          Dim newUserId As Guid = CType(newUser.ProviderUserKey, Guid)

          ' Insert a new record into UserProfiles
          Dim connectionString As String = ConfigurationManager.ConnectionStrings("SecurityTutorialsConnectionString").ConnectionString

          Dim updateSql As String = "UPDATE UserProfiles SET HomeTown = @HomeTown, HomepageUrl
               = @HomepageUrl, Signature = @Signature WHERE UserId = @UserId"

          Using myConnection As New SqlConnection(connectionString)
               myConnection.Open()
               Dim myCommand As 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()
          End Using
     End If
End Sub

上記のコードは、"完了" ステップに達したばかりのかどうかを判断することから始まります。 「設定」ステップの直後に「完了」ステップが行われるので、訪問者が「完了」ステップに達すると、彼女はちょうど「設定」ステップを完了したことを意味します。

このような場合は、 内 UserSettings WizardStepの TextBox コントロールをプログラムで参照する必要があります。 これは、最初に メソッドを FindControl 使用して プログラムで を参照 UserSettings WizardStepし、 内から TextBox を参照することで実現されます WizardStep。 TextBoxes が参照されたら、 ステートメントを実行 UPDATE する準備ができました。 ステートメントにはUPDATE、イベント ハンドラーの ステートメントCreatedUserと同じ数のパラメーターINSERTがありますが、ここでは、ユーザーによって提供されるホーム タウン、ホームページ、および署名の値を使用します。

このイベント ハンドラーを配置した状態で、ブラウザーからページに EnhancedCreateUserWizard.aspx アクセスし、ホーム タウン、ホームページ、署名の値を指定する新しいユーザー アカウントを作成します。 新しいアカウントを作成した後、ページに AdditionalUserInfo.aspx リダイレクトされます。ここで、入力したホーム タウン、ホームページ、署名情報が表示されます。

注意

現在、当社のウェブサイトには、訪問者が新しいアカウントを作成できる2つのページがあります: CreatingUserAccounts.aspxEnhancedCreateUserWizard.aspx。 Web サイトマップとログイン ページはページを CreatingUserAccounts.aspx ポイントしますが CreatingUserAccounts.aspx 、このページではユーザーにホーム タウン、ホームページ、署名情報の入力を求めるメッセージは表示されず、対応する行は に UserProfiles追加されません。 そのため、この機能を提供するようにページをCreatingUserAccounts.aspx更新するか、 ではなくCreatingUserAccounts.aspx、サイトマップとログイン ページを参照EnhancedCreateUserWizard.aspxするように更新します。 後者のオプションを選択する場合は、匿名ユーザーが Membership ページにアクセスできるように、フォルダーの Web.config ファイルを EnhancedCreateUserWizard.aspx 必ず更新してください。

まとめ

このチュートリアルでは、メンバーシップ フレームワーク内のユーザー アカウントに関連するデータをモデリングする手法について説明しました。 特に、ユーザー アカウントと一対多リレーションシップを共有するモデリング エンティティと、一対一リレーションシップを共有するデータについて説明しました。 さらに、この関連情報を表示、挿入、更新する方法を確認しました。SqlDataSource コントロールを使用する例もあれば、ADO.NET コードを使用する例もあります。

このチュートリアルでは、ユーザー アカウントの確認を完了します。 次のチュートリアルから始めて、ロールに注目します。 次のいくつかのチュートリアルでは、Roles フレームワークについて説明します。新しいロールを作成する方法、ユーザーにロールを割り当てる方法、ユーザーが属するロールを決定する方法、ロールベースの承認を適用する方法について説明します。

プログラミングに満足!

もっと読む

このチュートリアルで説明するトピックの詳細については、次のリソースを参照してください。

著者について

複数の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジと協力しています。 Scott は独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・自分自身 ASP.NET 24時間で2.0です。 Scott は、 または mitchell@4guysfromrolla.com のブログを http://ScottOnWriting.NET介してアクセスできます。

特別な感謝...

このチュートリアル シリーズは、多くの役立つ校閲者によってレビューされました。 今後の MSDN 記事の確認に関心がありますか? その場合は、 に行 mitchell@4GuysFromRolla.comをドロップしてください。