CreateUserWizard (almost) Figured Out – Part 2 – The .aspx File

This is the second in a series of posts about the CreateUserWizard.  The initial post provided an overview of the problem and the design.  This post covers the .aspx page with the CUW control declaration.  The final installment will cover the code-behind.

The CreateUserWizard (CUW) control declaration can be used with essentially no attributes other than ID and runat, and some empty placeholder templates, but then you have the demo mode (described in the the previous installment), not the real power the control is capable of.

By default the CUW presents a Create User button. Wanting a Cancel button as well, I set DisplayCancelButton to true and the CancelButtonText, CancelButtonType, and CancelDestinationPageUrl properties.  This latter sends you back to the Login page (outside the scope of this article) to try again.

Note that both the DuplicateUserNameErrorMessage and DuplicateEmailErrorMessage properties are the same.  This is a continuation of the facade of using the EmailAddress as the UserName.

I routinely insert logging in all the apps I develop.  It is invaluable in finding and fixing problems.  There I noticed that each new user was automatically getting logged in as soon as she was created. This was most definitely not what we wanted.  So I set the LogInCreatedUser to false.  (The default is true.) Problem solved.

Actually, this last point is not as unambiguous as I would like.  On redirection to the Login page after leaving the CreateUserPage,  the current user is the newly created user, even before she actually logs in, if LogInCreatedUser is set true in the CUW, but not if it is set to false.  However, one of the fields maintained in the security database for each user is “Online”, which tells if that user is currently online.  Although this boolean field is not visible in the WAT in Visual Studio, it can be seen if you get all the current users by calling Membership.GetAllUsers, and databind the resulting collection of Users to a GridView.  The details of doing so are outside the scope of this article, but suffice it to say that when looking at the security data in this way, a user newly created with LogInCreatedUser set false shows up as Online, even though she is not logged in.

Two of the many events offered by the CUW control are handled here: ContinueButtonClick and CreatingUser.  The former  is raised when the user clicks the Continue button after the user is created.  It just takes them back to the Login page.

The really interesting event is CreatingUser. It is raised before the user is created. As you will see in the final installment of this series, it is where all the validation is taken care of – both on the page and custom server-side.  If the potential new user does not pass muster, the account is not created.

In the production version of this app, every field on the page had at least a RequiredFieldValidator control.  In addition the phone number and e-mail address fields had a RegExValidator, and the two sets of comparison fields had a CompareValidator.  In other words, it was easy to fail validation just from the UI, not counting what is happening on the server.

In the version here, for the sake of brevity, I have removed all the validation controls except one, just to show you  how to handle validation errors on the page. It is not so obvious as it should be.

In this page, as in most ASP.NET pages, most of the control attributes are text strings. That is OK most of the time, but frankly, gets a bit tedious when using a lot of RegExValidator controls, because you have to copy and paste the same long, arcane string over and over.  Much better to store that value someplace and just refer to it in the control declaration, rather than enter the actual string.

This is easily accomplished with data binding, but the syntax is a little tricky.  Look at the ValidationExpression in the RegularExpressionValidator.

ValidationExpression='<%# Helper.strPhoneRegEx %>'/>

This topic continues with the final installment, which will cover the code-behind.

Here is the full content of CreateUser.aspx, minus most of the validation controls.

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
 CodeFile="CreateUser.aspx.cs" Inherits="CreateUser" %>

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
 <h2>CreateUserWizard Demo</h2>
 <!--  Keep in mind that EmailAddress is actually UserName -->
 <asp:CreateUserWizard ID="cuw" runat="server" CancelButtonStyle-CssClass="SmBtn"
  CancelButtonText="Cancel" CancelButtonType="Button" CancelDestinationPageUrl="~/Login.aspx"
  CreateUserButtonStyle-CssClass="SmBtn" DisplayCancelButton="true" DuplicateUserNameErrorMessage="This e-mail address is already in use."
  DuplicateEmailErrorMessage="This e-mail address is already in use." LoginCreatedUser="false"
  OnContinueButtonClick="btnContinue_Click" OnCreatingUser="cuw_CreatingUser">
  <WizardSteps>
   <asp:CreateUserWizardStep ID="cuws" runat="server">
    <ContentTemplate>
     <table cellpadding="3" cellspacing="0" border="0">
      <tr>
       <td align="left" colspan="3">
        Please enter your information.
        <br />
        All fields are required.
        <br />
        <br />
       </td>
      </tr>
      <tr>
       <td align="right">
        First Name:
       </td>
       <td colspan="2">
        <asp:TextBox ID="txtFirstName" runat="server" Width="200" />
       </td>
      </tr>
      <tr>
       <td align="right">
        Last Name:
       </td>
       <td colspan="2">
        <asp:TextBox ID="txtLastName" runat="server" Width="200" />
       </td>
      </tr>
      <tr>
       <td align="right">
        Phone Number:
       </td>
       <td>
        <asp:TextBox ID="txtPhoneNumber" runat="server" Width="200" />
        <asp:RegularExpressionValidator ID="revPhoneNumber" runat="server" ControlToValidate="txtPhoneNumber"
         CssClass="TxtWrn" Display="Dynamic" ErrorMessage="Invalid phone number" SetFocusOnError="true"
         ValidationExpression='<%# Helper.strPhoneRegEx %>' />
       </td>
       <td>
        Any of your phone numbers on record (with area code).
       </td>
      </tr>
      <tr>
       <!-- HACK --
        Since control requires UserName, but I want to use email address,
        will ask for it twice, but mislabeled. -->
       <td align="right">
        E-mail Address:
       </td>
       <td colspan="2">
        <asp:TextBox ID="UserName" runat="server" Width="200" />
        <asp:RegularExpressionValidator runat="server" ID="revEmail" ControlToValidate="UserName"
         CssClass="TxtWrn" Display="Dynamic" ErrorMessage="Invalid email address" ValidationExpression='<%# Helper.strEmailRegEx %>'
         SetFocusOnError="true" ToolTip="Invalid email address" />
       </td>
      </tr>
      <tr>
       <td align="right">
        Confirm E-mail:
       </td>
       <td colspan="2">
        <asp:TextBox ID="Email" runat="server" Width="200" />
       </td>
      </tr>
      <tr>
       <td align="right">
        Password:
       </td>
       <td>
        <asp:TextBox ID="Password" runat="server" TextMode="Password" Width="200" />
       </td>
       <td rowspan="2" valign="top">
        <%# Helper.strPassword6Chars1PunctHelpText%>
       </td>
      </tr>
      <tr>
       <td align="right">
        Confirm Password:
       </td>
       <td>
        <asp:TextBox ID="ConfirmPassword" runat="server" TextMode="Password" Width="200" />
       </td>
      </tr>
      <tr>
       <td align="right">
        Security Question:
       </td>
       <td>
        <asp:TextBox ID="Question" runat="server" Width="200" />
       </td>
       <td>
        Example: My High School
       </td>
      </tr>
      <tr>
       <td align="right">
        Security Answer:
       </td>
       <td>
        <asp:TextBox ID="Answer" runat="server" Width="200" />
       </td>
       <td>
        Example: Brookline High
       </td>
      </tr>
      <tr>
       <td align="center" colspan="3" style="color: red">
        <asp:Literal ID="ErrorMessage" runat="server" EnableViewState="False" />
       </td>
      </tr>
     </table>
    </ContentTemplate>
   </asp:CreateUserWizardStep>
   <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
    <ContentTemplate>
     Congratulations! Your Portal account has been created.
     <br />
     <br />
     <asp:Button ID="btnContinue" runat="server" Text="Back to Login" CssClass="SmBtn"
      CommandName="Continue" />
    </ContentTemplate>
   </asp:CompleteWizardStep>
  </WizardSteps>
 </asp:CreateUserWizard>
 <asp:Label ID="lblErrorMsg" runat="server" CssClass="TxtWrn" />
</asp:Content>
Advertisements

About Dan Hurwitz

A consultant specializing in .NET.
This entry was posted in Software Development and tagged , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s