When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs

ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
 
Print this Page!
Published: Wednesday, February 23, 2011

Using ASP.NET, Membership, and jQuery to Determine Username Availability


By Scott Mitchell


Introduction


Chances are, at some point you've tried creating a new user account on a website and were told that the username you selected was already taken. This is especially common on very large websites with millions of members, but can happen on smaller websites with common usernames, such as people's names or popular words or phrases in the lexicon of the online community that frequents the website. If the user registration process is short and sweet, most users won't balk when they are told their desired username has already been taken - they'll just try a new one. But if the user registration process is long, involving several questions and scrolling, it can be frustrating to complete the registration process only to be told you need to return to the top of the page to try a different username.

Many websites use Ajax techniques to check whether a visitor's desired username is available as soon as they enter it (rather than waiting for them to submit the form). This article shows how to implement such a feature in an ASP.NET website using Membership and jQuery. This article includes a demo available for download that implements this behavior in an ASP.NET WebForms application that uses the CreateUserWizard control to register new users. However, the concepts in this article can be applied to ad-hoc user registration pages and ASP.NET MVC.

Read on to learn more!

- continued -

Step 0: An Overview of Checking Username Availability


Before we dive into how to go about using Ajax techniques to check username availability when creating a new account, let's first take a moment to examine our end goal. The idea here is that when a user is registering a new account and enters their desired username they will be alerted if the username is already in use by another. The demo available for download at the end of this article has a web page named CreateAccount.aspx that contains a CreateUserWizard control. By default, the CreateUserWizard control does not preemptively check to see if the desired username is available. Instead, the username availability check is performed when the user clicks the "Create User" button.

Our goal is to check for username availability as soon as the user enters her desired username. In particular, we will use JavaScript to run some client-side code whenever focus in the username textbox is lost (such as when the user tabs out of the textbox or uses their mouse and clicks on an alternate element on the page). This JavaScript code will need to make an HTTP request to the web server, passing in the user's desired username. The server will then need to respond with a status message indicating whether the username is available or not. Finally, the client-side code will update the web page (if needed) based on the response returned from the server.

The screen shot below shows the CreateUserWizard control when the user first visits the CreateAccount.aspx page and has not entered any information into the form.

The CreateUserWizard control when the page is first loaded.

This next screen shot shows the CreateUserWizard control after the user has entered his desired username and tabbed out of the Username textbox. After leaving the textbox the JavaScript on the page asynchronously made a call back to the web server to determine the username availability. Since there already exists a user with the username "Scott" the user is displayed a message indicating such.

The CreateUserWizard control after the user has entered an unavailable username.

When the user changes the username to something unique, such as "Scotty", the "This username is already taken!" message is replaced with a short message letting them know that their new username is available.

The CreateUserWizard control after the user has entered an available username.

Note that the "This username is available" message only appears if the user enters an available username after entering an unavailable one. If the user started the process by entering an available username no message is displayed.

Step 1: Creating a Server-Side Service That Reports Username Availability


To determine whether a visitor's desired username is available we need a server-side service that can be invoked from client-side script that reports the availability of a specified username. As discussed in my article series Accessing Server-Side Data from Client Script, there are a variety of ways by which to implement such a server-side service, including using:
  • An ASP.NET web page
  • A generic HTTP handler
  • An ASMX Web Service
  • A WCF Service
For this demo I decided to use an ASP.NET web page as the server-side service, although any of the above options would work. In particular, I created a Services folder and, in there, added a new ASP.NET page named UsernameAvailable.aspx. This page has no markup defined in its .aspx file. Instead, it returns JSON that defines an object with a single Boolean property, available.

What Is JSON?
JSON, or JavaScript Object Notation, is an open, text-based serialization format, that is both human-readable and platform independent. It differs from XML in three important ways: it is much simpler to understand and implement than XML; it is less verbose, resulting in a slimmer payload; and, most importantly, data serialized in JSON can intuitively be parsed by JavaScript. For more information on JSON, refer to Building Interactive User Interfaces with Microsoft ASP.NET AJAX: A Look at JSON Serialization and An Introduction to JavaScript Object Notation (JSON) in JavaScript and .NET.

The UsernameAvailable.aspx page expects the desired username to be supplied in the querystring, like so: UsernameAvailable.aspx?desiredUsername. The page then looks to see if there exists a user with the username desiredUsername and returns an appropriate JSON payload.

For example, an HTTP request to UsernameAvailable.aspx?Scott returns the following JSON payload:

{
   "available": false;
}

Here, available is false since there already exists a user with the username "Scott". However, if you were to check on the availability of, say, Alexis - UsernameAvailable.aspx?Alexis - you'd get back a JSON payload reporting the username is available.

{
   "available": true;
}

The code for the UsernameAvailable.aspx page is quite simple and is contained entirely in its Page_Load event handler. It starts by setting the response's Content-Type attribute to application/json, which is the MIME type for JSON data.

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   Response.ContentType = "application/json"

   ...

Next, the username is read from the querystring and a string variable named output is defined.

   ...

   Dim username As String = Request.QueryString.ToString()
   Dim output As String = String.Empty

   ...

If a non-empty username was supplied, the Membership system is invoked to see if there exists a user with the desired username. Specifically, the Membership.GetUser method is called, passing in the desired username. If this method returns a MembershipUser object then that means that there exists a user with this username. If the Membership.GetUser method return Nothing (or null, in C# parlance) then the username is available! The output variable is assigned the appropriate JSON payload and this JSON is returned in the request via a call to Response.Write.

   ...

   'See if this user exists in the database    If Not String.IsNullOrEmpty(username) Then
      Dim usr As MembershipUser = Membership.GetUser(username)
      If usr Is Nothing Then
         output = "{""available"": true}"
      Else
         output = "{""available"": false}"
      End If
   End If
   Response.Write(output)
End Sub

Step 2: Customizing the CreateUserWizard Control to Show a "Username Taken" Message


The demo's CreateAccount.aspx page uses the CreateUserWizard control to register a new user account. By default, the CreateUserWizard displays an interface that prompts the user for their username and password, with additional fields for email and a security question and answer if the Membership system is configured to collect this information. However, the CreateUserWizard's user interface can be modified by converting the CreateUserWizard into a template. (To accomplish this, go to the Design view and, from the control's smart tag, click the "Customize Create User Step" link.)

To implement this functionality we need to convert the CreateUserWizard into a template so that we can access its Username textbox from client-side script and so that we can add the markup to display the "This username is already taken!" message, if needed. Converting the CreateUserWizard control into a template generates a lot of markup. The most pertinent bit for this discussion is the UserName TextBox, whose markup I show below. Note that the CreateUserWizard control is in a <table> and there is a table row (<tr>) for the username entry.

After converting the CreateUserWizard control to a template, add a table row for the "This username is already taken!" message. As the markup below shows, this table row has an id of usernameUnavailableRow and contains a <span> element whose id is set to availabilityMessage. We will access and modify these two HTML elements in client-side script if the visitor creating an account enters an unavailable username.

<asp:CreateUserWizard ID="cuWizard" runat="server" ...>
   <WizardSteps>
      <asp:CreateUserWizardStep runat="server">
         <ContentTemplate>
            <table style="font-family:Verdana;font-size:100%;">
               ...
               
               <tr>
                  <td align="right">
                     <asp:Label ID="UserNameLabel" runat="server" AssociatedControlID="UserName">User Name:</asp:Label>
                  </td>
                  <td>
                     <asp:TextBox ID="UserName" runat="server"></asp:TextBox>
                     <asp:RequiredFieldValidator ID="UserNameRequired" runat="server"
                        ControlToValidate="UserName" ErrorMessage="User Name is required."
                        ToolTip="User Name is required." ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                  </td>
               </tr>
               
               <tr id="usernameUnavailableRow">
                  <td> </td>
                  <td>
                     <span id="availabilityMessage"></span>
                  </td>
               </tr>

               
               ...
            </table>
         </ContentTemplate>
      </asp:CreateUserWizardStep>
      
      ...
</asp:CreateUserWizard>

Step 3: Calling the UsernameAvailable.aspx Service When Entering a Username


The final piece of the puzzle is to call the UsernameAvailable.aspx service whenever focus is lost from the UserName TextBox. This can be accomplished using jQuery's getJSON function, which takes two input parameters: the URL to request and the function to execute once the data is returned. The data returned is the object defined via the JSON payload - namely, an object with an available Boolean property. If available is false then we need to show the message "This username is already taken!"

The following jQuery performs these steps. Because this script is in the $(document).ready event handler it will run when the page is loaded in the browser.

$(document).ready(function () {
   var usernameUnavailableRow = $('#usernameUnavailableRow');
   var availabilityMessage = $('#availabilityMessage');
   var usernameTextbox = $('#<%=cuWizard.CreateUserStep.ContentTemplateContainer.FindControl("UserName").ClientID %>');

   usernameUnavailableRow.hide();

   usernameTextbox.blur(function () {
      if ($(this).val()) {
         $.getJSON('Services/UsernameAvailable.aspx?' + escape($(this).val()), function (results) {
            if (results.available) {
               if (usernameUnavailableRow.is(':visible')) {
                  availabilityMessage.html('This username is available.');
                  availabilityMessage.addClass('usernameAvailable');
                  availabilityMessage.removeClass('usernameTaken');
               }
            }
            else {
               usernameUnavailableRow.show();
               availabilityMessage.html('This username is already taken!');
               availabilityMessage.addClass('usernameTaken');
               availabilityMessage.removeClass('usernameAvailable');
            }
         });
      }
   });
});

The above code starts by referencing the usernameUnavailableRow table row (<tr>), the availabilityMessage <span> element, and the UserName textbox. The syntax for referencing the UserName textbox warrants some further discussion.

When we converted the CreateUserWizard control into a template it generated markup that included a TextBox control with its ID property set to UserName. While the TextBox control's ID is simply UserName, its rendered client-side id attribute turns into something different due to the fact that the TextBox control is within a template. To determine this value we have two options:

  1. If you are using ASP.NET 4 or beyond, set the TextBox's ClientIDMode property to Static. This ensures that the rendered client-side id attribute matches up precisely with the server-side ID value. See Take Control Of Web Control ClientID Values in ASP.NET 4 for more information on this technique.
  2. Use server-side code to output the appropriate client-side id attribute value into the script.
The code above uses option #2. Typically the code to emit the client-side id for a Web control would be: <%=webControlId.ClientID %>. However, in this case we have to do a bit more work because the UserName TextBox is buried in the CreateUserWizard control's template. Consequently, to get programmatic access to the TextBox we need get to the template itself and then use the FindControl method to dig out the Web control. cuWizard is the ID of the CreateUserWizard control, and its CreateUserStep property returns the wizard control's create user step. The create user step's ContentTemplateContainer property returns the template, which then can be searched via FindControl. Once we have the TextBox we can get the value of the client-side id attribute it will render via its ClientID property. Put it all together and we get: <%=cuWizard.CreateUserStep.ContentTemplateContainer.FindControl("UserName").ClientID %>. Whee!

After these three HTML elements have been referenced, the usernameUnavailableRow table row is hidden (by calling usernameUnavailableRow.hide()).

Next, an event handler for the usernameTextbox's blur event is created. If there is a value entered into the textbox then jQuery's getJSON function is called, which makes an asynchronous HTTP request to Services/UsernameAvailable.aspx, passing the value entered into the textbox through the querystring.

When the server returns its response, the function defined as the second parameter to getJSON is invoked. Here, the variable results contains the JSON object returned by the server. If the available property is true then we don't need to do anything unless the usernameUnavailableRow table row is visible, in which case we want to update the availabilityMessage <span> element to show the message "This username is available." Also, the usernameAvailable CSS class is added to the <span> and the usernameTaken CSS class is removed (if needed). These two CSS classes are defined in the Style.css stylesheet and are what makes the message italicized and displayed in a red or black color.

If the available property is false then the usernameUnavailableRow table row is displayed (via usernameUnavailableRow.show()) and the availabilityMessage <span> element's text and CSS classes are set accordingly.

And... that's it! Putting it all together, we have a customized user registration page and server-side service that work in tandem to seamlessly notify a user if their desired username is unavailable.

Happy Programming!

  • By Scott Mitchell


    Further Reading

  • Examining ASP.NET's Membership, Roles, and Profile
  • Accessing Server-Side Data from Client Script
  • Attachments

  • Download the code used in this article



  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article