デベロッパー 2006年8月29日 10:00

CreateUserWizardコントロールのマルチステッププロセス化

著者: Erich Peterson  オリジナル版を読む
2006年8月29日 10:00 付の記事
■海外internet.com発の記事

はじめに

 「より機能性と応答性に優れたユーザーフレンドリーなWebアプリケーションを作成する」という目標の実現に向けて、ASP.NET 2.0では、新しいサーバーコントロールが数多く追加されました。その1つがCreateUserWizardコントロールであり、これが今回の記事のテーマです。このコントロールになじみがない方のために簡単に説明しておきますが、CreateUserWizardはその名が示すとおり、ASP.NET 2.0のメンバシップシステムで新規ユーザーアカウントを作成するためのウィザードインターフェイスを実現するものです(Wizardコントロールとメンバシップシステムの詳細については、Scott Mitchellの記事『Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control』と『Examining ASP.NET 2.0’s Membership, Roles, and Profile』を参照してください)。

 この記事では、CreateUserWizardをマルチステッププロセスにカスタマイズする手順を紹介します。項目数の多いデータ入力フォームの場合は、いくつかのステップに分けるとユーザーの抵抗感が減り、プロセスを最後までやり遂げやすくなります。今回作成するプロセスのステップは次のとおりです。

  • 請求先住所の情報を収集するステップ
  • 発送先情報を収集するステップ
  • ユーザー情報を収集するステップ

 では本題に入りましょう。

準備

 この記事を深く理解し、サンプルコードを自分で試してみるためには、少なくとも、組み込みのメンバシッププロバイダ(SqlMembershipProvider)と「App_Data」フォルダのSQL Expressデータベースを使うようにWebサイトをセットアップする基本的な方法を知っている必要があります。このプロセスの詳細については、記事シリーズ『Examining ASP.NET 2.0’s Membership, Roles, and Profile』を参照してください。また、Scott Mitchellの記事『Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control』も、Wizardコントロールを総合的に理解するために役立ちます。Wizardコントロールは今回のサンプルにも出てきます。

CreateUserWizardの基本

 CreateUserWizardコントロールはWizardコントロールを拡張したもので、マルチステップのユーザー登録プロセスを作成するのに最適のコントロールです。しかし、次の図を見ても分かるように、既定のCreateUserWizardコントロールをページに配置しただけでは、実際のWebアプリケーションでは使い物になりません。

 このように、入力するフィールドがUser Name(ユーザー名)、Password(パスワード)、E-mail(メールアドレス)、Secret Question(秘密の質問)、Secret Answer(秘密の質問の答え)しかないのです。しかし幸いなことに、このコントロールはテンプレート化されていて、レイアウトを変更したり、入力するフィールドの数を増やしたり、マルチステッププロセスに作り変えたりすることができます。このコントロールの最も素晴らしいところは、メンバシッププロバイダとのシームレスな統合を実現することです(詳しくは後述)。

 CreateUserWizardコントロールを最初にページ上に配置したときに生成されるマークアップを次に示します。

<asp:CreateUserWizard ID="CreateUserWizard1" runat="server">
  <WizardSteps>
    <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
    </asp:CreateUserWizardStep>
    <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
    </asp:CompleteWizardStep>
  </WizardSteps>
</asp:CreateUserWizard>

 この宣言から、CreateUserWizardコントロールのカスタマイズ方法が想像できるのではないでしょうか。まず<WizardSteps>タグに注目してください。このタグの内側に、ユーザー登録プロセスのすべてのステップを記述します。その次に書かれているのは、登録プロセスの最初のステップです。ここでは次のように宣言されています。

<asp:CreateUserWizardStep ID="CreateWizardStep1" runat="server">
</asp:CreateUserWizardStep>

 このステップは、既定では、先ほど紹介したフィールド群(User Name、Passwordなど)を表示します。その後、[Create User]ボタンがクリックされると、そのユーザーを表す適切なレコードをSQL Expressデータベース内に作成します。最後に、次のように宣言されたステップがあります。

<asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
</asp:CompleteWizardStep>

 このステップは、既定では、「Your account has been successfully created(アカウントが正常に作成されました)」というメッセージと[Continue]ボタンを表示します。[Continue]ボタンがクリックされると、CreateUserWizardコントロールのContinueDestinationPageUrlプロパティに指定されているページへとユーザーを導きます。

CreateUserWizardコントロールのカスタマイズ

 それでは、ウィザード内のステップをカスタマイズする方法を見ていきましょう。<asp:WizardStep>要素を追加することで、ユーザー登録プロセスに新しいステップを追加します。例えば、ユーザー登録プロセスの第1ステップとして請求先情報を収集するためには、既存のステップの前に次のステップを追加します。

<asp:WizardStep ID="CreateUserWizardStep0" runat="server">
  <table>
    <tr>
      <th>Billing Information</th>
    </tr>
    <tr>
      <td>Billing Address:</td>
      <td>
        <asp:TextBox runat="server" ID="BillingAddress" MaxLength="50" />
        <asp:RequiredFieldValidator runat="server"
          ID="RequiredFieldValidator1" ControlToValidate="BillingAddress"
          ErrorMessage="Billing Address is required." />
      </td>
    </tr>
    <tr>
      <td>Billing City:</td>
      <td>
        <asp:TextBox runat="server" ID="BillingCity"
          MaxLength="50" Columns="15" />
        <asp:RequiredFieldValidator runat="server"
          ID="RequiredFieldValidator2" ControlToValidate="BillingCity"
          ErrorMessage="Billing City is required." />
      </td>
    </tr>
    <tr>
      <td>Billing State:</td>
      <td>
        <asp:TextBox runat="server" ID="BillingState"
          MaxLength="25" Columns="10" />
        <asp:RequiredFieldValidator runat="server"
          ID="RequiredFieldValidator3" ControlToValidate="BillingState"
          ErrorMessage="Billing State is required."  />
      </td>
    </tr>
    <tr>
      <td>Billing Zip:</td>
      <td>
        <asp:TextBox runat="server" ID="BillingZip"
          MaxLength="10" Columns="10" />
        <asp:RequiredFieldValidator runat="server"
          ID="RequiredFieldValidator4" ControlToValidate="BillingZip"
          ErrorMessage="Billing Zip is required." />
      </td>
    </tr>
  </table>
</asp:WizardStep>

 このWizardStep(IDプロパティの値はCreateUserWizardStep0)の内側に、今回のマルチステッププロセスの第1ステップで必要とされるすべての入力コントロールとRequiredFieldValidatorを配置します。具体的には、ユーザーが請求先の住所(番地、市、州、郵便番号)を入力するためのフィールドを用意し、これらをすべて必須フィールドにします。

 ユーザーの発送先情報を収集するには、これとほとんど同じ<asp:WizardStep>を、最初に紹介した<asp:WizardStep>の直後に追加します。この発送先情報収集ステップでは、ユーザーに発送先の住所(番地、市、州、郵便番号)とその他の発送関連の情報の入力を求めます。このステップのマークアップについての説明は省略します。このサンプルの完全なソースコードは、記事の冒頭に示されているリンクからダウンロードすることができます。この新しいWizardStepのIDプロパティはCreateUserWizardStep1にします。これでは同じページ上にあるCreateUserWizardStepのIDプロパティの値と衝突してしまうので、CreateUserWizardStepのIDプロパティをCreateUserWizardStep2に変更します。これで最初の2つのカスタムステップが定義できました。

 最初に作成したCreateUserWizardStepをそのままにして、既定のフィールドを表示するだけでもよいのですが、前の2つのステップに合わせてレイアウトをカスタマイズしてみましょう。これにより、後でこのステップを自分でもっと大きくカスタマイズするときに必要な知識が身につくと思います。このステップをカスタマイズするには、まずこのステップ内に<ContentTemplate>タグを追加し、その内側に必要なコードをすべて記述します。このステップをカスタマイズするために必要なマークアップは次のようになります。細かい内容は後で説明します。

<asp:CreateUserWizardStep ID="CreateUserWizardStep2" runat="server">
  <ContentTemplate>
    <table>
      <tr>
        <th>User Information</th>
      </tr>
      <tr>
        <td>Username:</td>
        <td>
          <asp:TextBox runat="server" ID="UserName" />
          <asp:RequiredFieldValidator runat="server"
            ID="RequiredFieldValidator9" ControlToValidate="UserName"
            ErrorMessage="Username is required." />
        </td>
      </tr>
      <tr>
        <td>Password:</td>
        <td>
          <asp:TextBox runat="server" ID="Password" TextMode="Password" />
          <asp:RequiredFieldValidator runat="server"
            ID="RequiredFieldValidator10" ControlToValidate="Password"
            ErrorMessage="Password is required." />
        </td>
      </tr>
      <tr>
        <td>Confirm Password:</td>
        <td>
          <asp:TextBox runat="server" ID="ConfirmPassword"
            TextMode="Password" />
          <asp:RequiredFieldValidator runat="server"
            ID="RequiredFieldValidator13"
            ControlToValidate="ConfirmPassword"
            ErrorMessage="Confirm Password is required." />
        </td>
      </tr>
      <tr>
        <td>Email:</td>
        <td>
          <asp:TextBox runat="server" ID="Email" />
          <asp:RequiredFieldValidator runat="server"
            ID="RequiredFieldValidator11" ControlToValidate="Email"
            ErrorMessage="Email is required." />
        </td>
      </tr>
      <tr>
        <td>Question:</td>
        <td>
          <asp:TextBox runat="server" ID="Question" />
          <asp:RequiredFieldValidator runat="server"
            ID="RequiredFieldValidator12" ControlToValidate="Question"
            ErrorMessage="Question is required." />
        </td>
      </tr>
      <tr>
        <td>Answer:</td>
        <td>
          <asp:TextBox runat="server" ID="Answer" />
          <asp:RequiredFieldValidator runat="server"
            ID="RequiredFieldValidator14" ControlToValidate="Answer"
            ErrorMessage="Answer is required." />
        </td>
      </tr>
      <tr>
        <td colspan="2">
          <asp:CompareValidator ID="PasswordCompare"
            runat="server" ControlToCompare="Password"
            ControlToValidate="ConfirmPassword" Display="Dynamic"
            ErrorMessage="The Password and Confirmation Password must match.">
          </asp:CompareValidator>
        </td>
      </tr>
      <tr>
        <td colspan="2">
          <asp:Literal ID="ErrorMessage" runat="server"
            EnableViewState="False"></asp:Literal>
        </td>
      </tr>
    </table>

 このコードにはレイアウト用のHTMLタグ(<table>など)も含まれていますが、それ以外の部分は、新規ユーザーを作成してエラー発生時にユーザーにフィードバックするために必要な情報を表しており、これらの情報がASP.NET 2.0のSqlMembershipProviderに引き渡されます。このコードで重要なのは、各コントロールに適切な名前を付け(つまり正しいIDを指定し)、どのコントロールがどのユーザー属性を表しているかをASP.NETが認識できるようにすることです。例えば1つ目のTextBoxにはID="Username"と指定されています。このようなIDを指定すると、ASP.NETは、このTextBoxがユーザーのユーザー名を表していることを認識します。ID="Password"と指定されているTextBoxも同様です。ASP.NETは、このTextBoxに基づいてユーザーのパスワードを作成すればよいということを認識します。コードの残りの部分でも、サーバーコントロールのIDプロパティを見れば、それが何に使われるものであるかが分かります。後でこのステップを自分で大幅にカスタマイズする場合は(例えばニュースレターの配信を希望するかどうかを尋ねるCheckBoxを配置するなど)、最初の2つのステップを追加したときと同様の方法で、サーバーコントロールとマークアップを追加します。

カスタムユーザーデータの保存

 ここまでの段階で、CreateUserWizardコントロールをカスタマイズして、請求先と発送先の情報をユーザーに尋ねることができるようになりました。しかし、既定のCreateUserWizardコントロールは、既定のユーザー属性(ユーザー名、メールアドレス、パスワード、秘密の質問とその答えなど)を備えた新規ユーザーをメンバシップシステムに追加するだけです。SqlMembershipProviderは、これらの基本的なユーザー属性を格納するデータベーステーブルをあらかじめ用意しています。追加のユーザー属性を保存するためには、ASP.NET 2.0のプロファイルシステムを使用するか、この追加データを格納する独自のデータベーステーブルを作成する必要があります。今回は、後者の方法を使用します。

 CreateUserWizardで収集した追加情報を保存するために、今回のサンプルプロジェクトのSQL Server Expressデータベース(「App_Data」フォルダの「ASPNETDB.MDF」)内に「UserAddresses」という名前のテーブルを作成しました。このテーブルのスキーマは次のようになっています。

 「UserAddresses」テーブルのUserId列は、このテーブルの主キーであり、「aspnet_Users」テーブル内のユーザーを指す外部キーでもあります。この追加データを挿入するには、CreateUserWizardStepの内側のどこかでSqlDataSourceサーバーコントロールを使用して、メンバシップシステム内にユーザーアカウントが作成された後にカスタムのユーザー属性を挿入します(SqlDataSourceコントロールの詳細については、Scott Mitchellの記事シリーズ『Accessing and Updating Data in ASP.NET 2.0』を参照してください)。

 次のマークアップでは、InsertCommandプロパティを使用して「UserAddresses」テーブルに新規レコードを追加するSqlDataSourceコントロールを追加しています。

<asp:SqlDataSource ID="InsertExtraInfo" runat="server"
  ConnectionString="<%$ ConnectionStrings:ASPNETDBConnectionString1 %>"
  InsertCommand="INSERT INTO [UserAddresses] ([UserId], [BillingAddress], 
[BillingCity], [BillingState], [BillingZip], [ShippingAddress], 
[ShippingCity], [ShippingState], [ShippingZip]) VALUES (@UserId, 
@BillingAddress, @BillingCity, @BillingState, @BillingZip, 
@ShippingAddress, @ShippingCity, @ShippingState, @ShippingZip)"
  ProviderName="<%$ ConnectionStrings:ASPNETDBConnectionString1.ProviderName %>">
  <InsertParameters>
    <asp:ControlParameter Name="BillingAddress" Type="String"
      ControlID="BillingAddress" PropertyName="Text" />
    <asp:ControlParameter Name="BillingCity" Type="String"
      ControlID="BillingCity" PropertyName="Text" />
    <asp:ControlParameter Name="BillingState" Type="String"
      ControlID="BillingState" PropertyName="Text" />
    <asp:ControlParameter Name="BillingZip" Type="String"
      ControlID="BillingZip" PropertyName="Text" />
    <asp:ControlParameter Name="ShippingAddress" Type="String"
      ControlID="ShippingAddress" PropertyName="Text" />
    <asp:ControlParameter Name="ShippingCity" Type="String"
      ControlID="ShippingCity" PropertyName="Text" />
    <asp:ControlParameter Name="ShippingState" Type="String"
      ControlID="ShippingState" PropertyName="Text" />
    <asp:ControlParameter Name="ShippingZip" Type="String"
      ControlID="ShippingZip" PropertyName="Text" />
  </InsertParameters>
</asp:SqlDataSource>

 InsertParameterShippingAddressShippingCityShippingStateShippingZipの値は、今回のCreateUserWizardの第2ステップのコントロールから取得されます(ここでは説明を省略します)。

 ユーザーアカウントがメンバシップシステムに追加されると、CreateUserWizardのOnCreatedUserイベントが発生します。そこで、このイベントに関するイベントハンドラを作成し、SqlDataSourceのInsert()メソッドを呼び出します。これにより、ユーザーアカウントがメンバシップシステムに追加された後に、カスタムのユーザー属性が「UserAddresses」テーブルに追加されます。

protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
{
  TextBox UserNameTextBox =
    (TextBox)CreateUserWizardStep2.ContentTemplateContainer
      .FindControl("UserName");
  SqlDataSource DataSource =
    (SqlDataSource)CreateUserWizardStep2.ContentTemplateContainer
      .FindControl("InsertExtraInfo");

  MembershipUser User = Membership.GetUser(UserNameTextBox.Text);
  object UserGUID = User.ProviderUserKey;

  DataSource.InsertParameters.Add("UserId", UserGUID.ToString());
  DataSource.Insert();
}

 このイベントハンドラでは、CreateUserWizardStep2ステップから新しいユーザーのユーザー名を取得し、それをMembership.GetUser(userName)メソッドに渡しています。Membership.GetUser(userName)メソッドは、指定されたユーザーに関するUserIdなどの情報を返します。その後、メンバシップユーザーのUserIdをSqlDataSourceコントロールのUserIdパラメータに割り当て、「UserAddresses」テーブルへのレコードの挿入を実行します。

 お好みの色を追加してプロジェクトを実行すると、次の図のようなフォームが表示されます。

 各ステップを順にたどったり、前のステップに戻ったりすることができ、フィールドに必要な情報を入力してウィザードを完了すると、新規ユーザーを作成することができます。ユーザーが作成できたら、データベーステーブルを調べて、「UserAddresses」テーブルに新しいレコードが追加されていることを確認しましょう。

まとめ

 今回の記事では、ASP.NET 2.0のCreateUserWizardサーバーコントロールをカスタマイズする方法を順を追って説明しました。具体的には、請求先情報と発送先情報を収集する2つの独立したステップを作成しました。さらに、ユーザーの入力内容を収集して、ASP.NETのユーザーテーブルに対する外部キーを備えたデータベーステーブルに保存しました。

 それでは、ハッピープログラミング!

参考資料

著者紹介

Erich Peterson(Erich Peterson)


トップページ | 画面トップ

Copyright 2008 Jupitermedia Corporation All Rights Reserved. http://www.internet.com/