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

作成者: 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 Frameworkには、プロファイル データをSqlProfileProviderSQL Server データベースに格納する sthat が付属しています。 実際、データベースには(aspnet_Profile)によってSqlProfileProvider使用されているテーブルが既に含まれています。これは、アプリケーション サービスを「Creating the Membership Schema in 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.config が既に SecurityTutorials 定義されています。 この接続文字列名 – は 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 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;
}

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

注意

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

ブラウザーを使用してページに 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 戻り、Bruce としてログインします。 図 13 に示すように、Bruce の設定が表示されます。

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

図 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 作成されます。 すべてのパラメーターのソースを [なし] に設定したまま、[OK] ボタンをクリックしてダイアログ ボックスを完了します。

SqlDataSource の UpdateCommand パラメーターと UpdateParameters を指定する

図 14: SqlDataSource の UpdateCommandUpdateParameters を指定します (クリックするとフルサイズの画像が表示されます)

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

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

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

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

これを解決するには、Visual Studio に戻り、DetailsView の上に Label コントロールを追加します。 を IDSettingsUpdatedMessage設定し、その Text プロパティを "設定が更新されました" に、プロパティ VisibleEnableViewState プロパティを に 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 コントロールのプロパティは 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。 この名前空間をページの分離コード クラス (つまり) using System.Data.SqlClient;にインポートする必要がある場合があります。

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

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指定する必要があるため、この値が必要です。

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

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

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

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

GuestbookComments テーブルでゲストブックのコメントを確認できます

図 17: テーブルにゲストブックのコメントを GuestbookComments 表示できます (フルサイズの画像を表示する をクリックします)

注意

ユーザーが潜在的に危険なマークアップ (HTML など) を含むゲストブック コメントを挿入しようとすると、ASP.NET は を HttpRequestValidationExceptionスローします。 この例外の詳細、スローされる理由、およびユーザーが危険な可能性のある値を送信できるようにする方法については、「 検証の要求に関するホワイトペーパー」を参照してください。

手順 5: 既存のゲストブックコメントを一覧表示する

コメントを残すだけでなく、ページにアクセスする Guestbook.aspx ユーザーもゲストブックの既存のコメントを表示できる必要があります。 これを実現するには、ページの下部に という名前 CommentList の ListView コントロールを追加します。

注意

ListView コントロールは、バージョン 3.5 ASP.NET 初めて使用できます。 これは、非常にカスタマイズ可能で柔軟なレイアウトで項目の一覧を表示するように設計されています。ただし、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 つのテーブルすべてがデザイン サーフェイスに追加されます。 、、および aspnet_Users テーブルの間GuestbookCommentsUserProfilesには外部キー制約があるため、クエリ ビルダーによってこれらのテーブルが自動的JOINに作成されます。

残っているのは、返す列を指定することです。 GuestbookCommentsテーブルから 、Body、および 列をSubject選択しCommentDate、テーブルから 、HomepageUrl、および Signature 列をUserProfilesHomeTownし、 からaspnet_Usersを返しますUserName。 また、クエリのSELECT最後に "ORDER BY CommentDate DESC" を追加して、最新の投稿が最初に返されるようにします。 これらの選択を行った後、Query Builder インターフェイスは図 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結果のマークアップは、 の itemPlaceholder コントロールにLayoutTemplate配置されます。 に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ページで使用されるクエリでは、 Guestbook.aspxINNER JOIN使用して、、UserProfiles、および の各テーブル間で関連レコードをGuestbookCommentsaspnet_Users結合します。 にレコードUserProfilesがないユーザーがゲストブック コメントを作成した場合、 と に一致するレコードがある場合にのみレコードが返GuestbookCommentsされるためINNER JOIN、コメントは ListView にUserProfilesaspnet_Users表示されません。 手順 3 で説明したように、ユーザーがレコードを持っていない場合、ページでUserProfilesAdditionalUserInfo.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 の既定のユーザー インターフェイスは、訪問者に必要な情報を求めます。 この情報が提供されると、コントロールは内部的に Membership フレームワークに新しいユーザー アカウントを作成します。コードを 1 行記述する必要はありません。

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

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

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

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 オブジェクトがインスタンス化され、コマンドが実行されます。 このコードでは、および @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 しいを追加するには、スマート タグから [追加/削除 WizardSteps] リンクをクリックしてコレクション エディターを WizardStep 起動します。 そこから、ウィザードの手順を追加、削除、または並べ替えることができます。 これは、このチュートリアルで使用するアプローチです。

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

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

重要な点の 1 つは、CreateUserWizard コントロールが、ユーザーの作成ボタンが 内からクリックされたときに、ユーザー アカウントの作成プロセスを CreateUserWizardStep実行することです。 の後CreateUserWizardStepに が追加WizardStepされているかどうかは関係ありません。

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

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

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

図 21: 追加 WizardStep の が の前 CreateUserWizardStep にある場合の CreateUserWizard ワークフロー (フルサイズの画像を表示する をクリックします)

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

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

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

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

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

CreateUserWizard コントロールのスマート タグから、[追加/削除 WizardStep ] を選択すると、[コレクション エディター] ダイアログが WizardStep 表示されます。 新 WizardStepしい を追加し、 を IDUserSettings設定し、そのを Title "Your Settings" に、その を StepType に設定します Step。 次に、図 23 に示すように、("新しいアカウントにサインアップ") の後 CreateUserWizardStep 、("Complete") の前 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したときにこの手順が表示されるように、必ず "新しいアカウントにサインアップする" に設定してください。

、、および Signatureという名前HomeTownHomepageUrlの 3 つの 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新しい行が追加されますが、データベース NULLHomeTownは 、 HomepageUrl、および Signatureになります。 ホーム タウン、ホームページ、署名に入力された値は使用されません。 結果は、および Signature フィールドがまだ指定されていないレコードHomepageUrlHomeTownを持つUserProfiles新しいユーザー アカウントです。

ホーム タウン、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 コントロールをプログラムで参照する必要があります。 これは、最初に メソッドを 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 必ず更新してください。

まとめ

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

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

幸せなプログラミング!

もっと読む

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

著者について

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

特別な感謝...

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