Wednesday, June 24, 2009

ASP.NET user name availability check using WCSF Validation Bundle

An average web site offering membership and protected content for its members requires users to sign up by visiting a sign-up or register page that allows a user to enter some information and create an account. A couple of pieces if information that users are commonly asked to enter are a User name or Login name and user's email. One potential problem with such user input is checking that entered login name and/or email address are available for registration and haven't been used by other users. When it's the case multiple attempts of entering available values can be very annoying and frustrating for users even making them to refuse registration on a web site. So improving user experience when validating login name and email is quite an important task.

There is a number of ways of how to implement a user input validation and display an error message, for instance that one suggested by Dave Ward. In this post I am going to show you another relatively simple and elegant solution that provides with both  reliability and reasonably pleasant user experience.

The solution is based on using a ServerSideValidationExtender control from Web Client Software Factory validation bundle. The ServerSideValidationExtender control allows asynchronious invocation of a server-side validation handler that performs a validation right after a user finished entering data without a postback thus signifcantly improving the user experience at the same time leveraging robustness and security of server-side validation.

Code example

For this example I will be using a really simple markup code:

<asp:Label ID="lblEmail" runat="server" Text="Email: ">
<asp:TextBox ID="txtEmail" runat="server">
<asp:CustomValidator ID="cvEmail" runat="server"
ErrorMessage="Email is already used"
ControlToValidate="txtEmail"
onservervalidate="cvEmail_ServerValidate" />
<wcsf:ServerSideValidationExtender ID="ssveEmail"
TargetControlID="cvEmail"
ValidateEmptyText="false" runat="server" />
<br />
<asp:Label ID="lblLogin" runat="server" Text="Login: ">
<asp:TextBox ID="txtLogin" runat="server">
<asp:CustomValidator ID="cvLogin" runat="server"
ErrorMessage="Login name is already used"
ControlToValidate="txtLogin"
onservervalidate="cvEmail_ServerValidate" />
<wcsf:ServerSideValidationExtender ID="ssveLogin"
TargetControlID="cvLogin"
ValidateEmptyText="false" runat="server" />
<br />
<asp:Button ID="cmdRegister" runat="server" Text="Register" />

that effectively results in that UI in a browser:


For each TextBox control requiring asynchronious server-side validation I've added a CustomValidator control and a ServerSideValidationExtender that has its TargetID property set to an ID of a corresponding CustomValidator control.

Next I've added some code to the validation handlers for the CustomValidator controls to the page's code behind and that's it:

protected void cvEmail_ServerValidate(object source,
ServerValidateEventArgs args)
{
args.IsValid = string.IsNullOrEmpty(
Membership.GetUserNameByEmail(args.Value));
}

protected void cvLogin_ServerValidate(object source,
ServerValidateEventArgs args)
{
args.IsValid = Membership.GetUser(args.Value) == null;
}

Note that the IsValid equals true when a user can not be found. The server-side validation handler is being executed asynchroniously every time a corresponding TextBox loses its focus and if validation has failed (meaning that a user was found and login name or email is not available) a corresponding error message is displayed immediately on the page without a postback so a user does not have to click a submit button and wait for the page to render again to see the result of the validation.


The only trick here is that in the server-side validation handler we can only access a value of the control being validated because values of other controls on the page haven't been updated on the server side (no postback, remember?!).

Note. In the production code you may want to add some layout and styling to your HTML markup, and of course there will be perhaps other input boxes on a form with may be more validator controls but the approach won't change: no additional code required, the same well-known validation pattern but with nicer user experience. I would also recommend to implement a simple but very useful change to the ServerSideValidationExtender control suggested by Jarod Ferguson.

4 comments:

  1. Thanks for this. Have you managed to get it working with the latest version of the Toolkit (3.0.30512.0)? I managed to get my site to build with the AjaxControlToolkit.WCSFExtensions assembly after adding a binding redirect to web.config.

    I cannot add controls in that dll into the Toolbox in VS2008 (due to the difference in Toolkit version - which I guess I should expect) - but the real issue is that when I add a ServerSideValidationExtender to my page I still get a build error that version 3.0.30512.0 (or one of its dependents) could not be loaded as the manifest definition does not match the assembly reference. I thought the binding redirect should have fixed this. Any clues gratefully received.

    Jon

    ReplyDelete
  2. To jstranger: Since WCSF is available with the source code what I did is simply recompiled the project with the newest version of Ajax Control Toolkit. After that everything works OK.

    ReplyDelete
  3. Many thanks for the reply - sounds like the best approach. I have downloaded and installed WCSF but I am not at all clear what I need to compile/build. I ran the SourceInstall msi and selected only the Validation Quickstart, the Web Client Factory Guidance Packages and the Library Binaries for Source Code, since I am only interested in the validation support. But I do no know which project(s) I need. Could you point me at the relevant documentation?

    ReplyDelete
  4. Sorry - just realised that I needed the BlockInstall msi. All sorted.

    ReplyDelete