Customizing the CreateUserWizard ControlBy Erich Peterson
In the never ending quest to create web applications that are more functional, responsive, and user-friendly, ASP.NET 2.0 has added a multitude of new server controls to help us achieve those goals. One of these new controls is the CreateUserWizard and is the focus of this article. For those unfamiliar with the control, CreateUserWizard, as its name implies, provides a wizard interface for creating a new user account in the ASP.NET 2.0 membership system. (See Scott Mitchell's articles Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control and Examining ASP.NET 2.0's Membership, Roles, and Profile for more information on the Wizard control and on the membership system.)
In this article we will be stepping through the process of customizing the CreateUserWizard into a multi-step process. Some believe breaking up a large data entry form into a multi-step process is less off-putting to the user and encourages them to see the process to its end. The process steps we will be creating will include:
- A step which will gather billing address information,
- Another for shipping information, and finally,
- One to collect user information
To understand this article fully and to be able to work through the code yourself, we assume that you know at least the basics of setting up your website to use the built-in membership provider (
SqlMembershipProvider) for use with a SQL Express database in your
App_Datafolder. For more information on this process, please check out the Examining ASP.NET 2.0's Membership, Roles, and Profile article series. Also, reading Scott's Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control will help greatly in your overall understanding of the Wizard control, which is shown in our examples here as well.
Basics of the CreateUserWizard
The CreateUserWizard control extends the Wizard control, and as such lends itself very nicely in creating a multi-step user registration process. If you simply place the CreateUserWizard control on a page, the default behavior of it can seem quite unrealistic for use in real-world web applications (as can be seen in the following figure).
That is, it only has inputs for the: User Name, Password, E-mail, and Secret Question and Answer. But alas, the control can be "templated" to change the layout and to require more information to be gathered, and can be turned into a multi-step process. Best of all, the control will still provide us seamless integration with our membership provider (more on that later). The following shows the markup that is created when the control is first placed on a page:
From this declaration, we can already guess a bit as to how we might customize the control. First we see the
<WizardSteps> tags, in which all the steps of our user registration process must be enclosed. Next,
we see the first step of our process declared by:
This is the step that by default, displays the inputs we talked about earlier (i.e. User Name, Password, etc…), and after the "Create User" button is pressed, will then create the appropriate records in the SQL Express database (which will represent that user). Lastly, we see the step declared by:
This step by default, displays the message: "Your account has been successfully created" and provides a button labeled "Continue",
which when pressed, will take the user to the page defined by the
property of the CreateUserWizard control.
Customizing the CreateUserWizard Control
Let us now take a look at how we might customize the steps in our wizard. We can add new steps to the user registration process by adding new
<asp:WizardStep>elements. For example, to start the user registration process by collecting billing information, we can add the following step before all current steps:
Inside this WizardStep (whose
ID property is set to
CreateUserWizardStep0), we have placed all of the input controls and RequiredFieldValidator's that we would like the first
step of our multi-step process to contain. Specifically we are asking the user to input their billing address, city, state,
and zip code; along with requiring all of those fields.
To collect the user's shipping information we can add an almost identical
<asp:WizardStep> immediately after
the previously mentioned one. This shipping information step will prompt the user shipping address, city, state, and other shipping-related
information. Let's omit this step's markup for brevity; the entire source code for this sample can be downloaded at the end
of the article. Give this new WizardStep an
conflict with the CreateUserWizardStep's
ID which is on the page as well; just rename the CreateUserWizardStep's
CreateUserWizardStep2. With that we are done defining our first two custom CreateUserWizard steps!
Although we could leave the CreateUserWizardStep alone and let it display its default inputs, let us customize the layout to
match the other two steps. In doing so, it will provide you with the knowledge needed to later customize this step further
as well, if you so chose to. To start the customization process of this step, we must add the
tag within this step and then place all of our code inside it. Let us take a look at the markup that is required to customize
this step and then explain.
As mentioned, minus the layout HTML (i.e.
<table>), the code listed above is what is needed to give
SqlMembershipProvider the proper information to create a new user and to provide feedback to the
user on errors that may occur. What is the most important concept to understand in the code shown above, is that we must
name our controls properly (using the correct
IDs), so ASP.NET knows which input is for which user attribute.
Take the TextBox above with an
ID="Username" as an example. By giving it that
ID, ASP.NET knows
that, that TextBox will contain the user's username. The same is true about the TextBox with
ASP.NET knows to use that TextBox to create the user's password. So, now looking at the rest of the code, you can tell by
the server controls
ID's, what they are used for. If you now wanted to customize this step further (with say a
CheckBox, asking if the user would like to receive your newsletter), you could do so by adding the applicable server
controls and markup, just like we did in the first two customized steps.
Storing Custom User Data
At this point we have customized the CreateUserWizard control to prompt the user for billing and shipping information, but, by default, the CreateUserWizard control will only add a new user to the membership system with the default user attributes (username, email, password, security question and answer, and so on). The
SqlMembershipProviderwe are using already has database tables to store the core user-related settings. In order to store the additional user attributes we either need to use ASP.NET 2.0's profile system or create our own database tables to hold this additional data. For this article we will use the latter approach.
To help facilitate our storage of the extra information we are gathering in our CreateUserWizard, I have created an extra
table in the SQL Server Express database (
ASPNETDB.MDF, located in the
App_Data folder of the project) named
UserAddresses, with the following schema:
UserId column in
UserAddresses acts as a both a primary key for the
table and as a foreign key that points to the user in the
aspnet_Users table. To insert this additional data,
we can use a SqlDataSource server control somewhere inside of the CreateUserWizardStep that will insert the custom user attributes
after the user account has been created in the membership system. (For more information on the SqlDataSource control see
Scott Mitchell's Accessing and Updating Data in ASP.NET 2.0
The following markup creates a SqlDataSource control whose
InsertCommand will add a new record to the
InsertParameter values are coming from controls in the second step of our CreateUserWizard, which we left out
After the user account has been added to the membership system, the CreateUserWizard fires its
Therefore, create an event handler for this event and invoke the SqlDataSource's
Insert() method, thereby causing
the additional user attributes to be added to the
UserAddresses table after the user account has been added to the
In this event handler, we simply grab the new user's username from the
CreateUserWizardStep2 step so that we
may pass it to the
returns information about the selected user, including their
We then assign the membership user's
UserId parameter of the SqlDataSource control and
initiate the insertion of the record into our
Once you add colors to your liking and run the project, you should see output similar to the following:
You can now go through each step and even go back to a previous step, filling out the fields, and finally creating the user.
After you are finished creating the user, be sure and look in your database table to see that a new record has been added
In this article, we stepped through the process of customizing ASP.NET 2.0's CreateUserWizard server control. We were able to create two separate steps for the collection of billing and shipping information. In addition, we were able to gather the inputs from the user and store them in a database table, which contained a foreign key to ASP.NET's users table.