Check Duplicate User Names In ASP.NET Web Pages Sites

5 (3 votes)

The Web Pages Starter Site template provides a useful starting point for developing a Razor Web Pages site that includes membership. But it doesn't include any mechanism for preventing duplicate user names. This article offers one solution to the problem that uses jQuery.

If you ask how to prevent duplicate user names in forums, one of the suggestions that is often put forward is to apply a unique constraint in the database column that holds the user name. Any attempt to submit a duplicate value will result in an exception being raised in the relevant database provider. You can catch this exception and show the user an appropriate message. This works - and you are always advised to add unique constraints to database columns that should hold unique values - but it's a fairly clunky solution. And many people feel that you should not use exceptions as a means to manage your business rules (myself included).

The solution featured in this article uses AJAX to query the database and to give the user immediate feedback when they enter their chosen user name. The AJAX call requests a page that exists purely to query the database to see if the selected user name is already in use. The solution also includes a server side chekc to ensure that users who have disabled JavaScript so not slip through the net. The solution requires a couple of amendments to the Register.cshtml file in the Starter Site, and the addition of 3 files. But first, the changes to the Register.cshtml page. The first change is in the inclusion of a JavaScript file called dupecheck.js (which will be created a bit later):

@* Remove this section if you are using bundling *@
@section Scripts {
    <script src="~/Scripts/jquery.validate.min.js"></script>
    <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
    <script src="~/Scripts/dupecheck.js"></script>

And the second is the server side check to see if the username is in use:

    ModelState.AddError("email", "User name is already taken");

I placed this in the if(IsPost) section just after the initial variables that represent the submitted values (email, password and confirmPassword) are declared. The code calls a function named IsDuplicate. The function is declared in a file called Functions.cshtml which is placed in a folder called App_Code:

@functions {
    public static bool IsDuplicate(string username){
        var db = Database.Open("StarterSite");
        var commandText = @"SELECT COUNT(Email) FROM UserProfile WHERE Email = @0";
        return (int)db.QueryValue(commandText, username) > 0;
Note that the name of the folder is important. The function returns a bool. The value of the bool is determined as a result if the SQL query which gets a count of the rows containing the provided user name. By default, the Starter Site uses a column called Email in the UserProfile table for the storage of user names. This function is also called in a separate file named DupeCheck.cshtml. This file is placed in the root of the site:


    Layout = null;
        var username = Request["username"];
        var result = Functions.IsDuplicate(username);
        Json.Write(new { isDupe = result }, Response.Output);

DupeCheck.cshtml is designed to work exclusively with AJAX. The code includes an instruction to nullify any layout pages that might have been set in a _PageStart file, and then it uses the IsAjax property to determine if the page has been requested via an AJAX call. If it has, it uses the IsDuplicate method to check the availability of the posted username and returns the result to the calling code. The result is an anonymous type that has one propery: isDupe, which is a boolean. The anonymous type is serialised to JSON by the Json helper.

The final part of the solution is the dupecheck.js file. This uses jQuery:

$(function () {
    $('#email').change(function () {
            { username: $(this).val() },
            function (data) {
                var emailValidation = $('span[data-valmsg-for="email"]');
                if (data.isDupe) {
                    if (emailValidation.hasClass('field-validation-valid')) {
                        emailValidation.text('That name is already taken!');
                } else {
                    if (emailValidation.hasClass('field-validation-error')) {

An event handler is attached to the change event of the user name input (which has an id if email in the Starter Site). The current value is posted to the DupeCheck.cshtml page via AJAX. The code above checks the response from the server to see if the value is a duplicate, and if it is, an appropriate error message is displayed to the user.

And there it is - a clean way to provide users with immediate feedback on the availability of their chosen user name.


You might also like...

Date Posted:
Last Updated:
Posted by:
Total Views to date: 28441


- Fish

Why do the "IsAjax" check?
This somehow related to security? And if how how does it become more secure?

- Mike


As it says in the article, the IsAjax property returns true if the request was made by AJAX. That means that people can't simply put in their browser and request the file. Also, by default, cross origin AJAX requests are not allowed, so it acts as protection against misuse.

- satyabrata

Nice post.very helpful.

- Kelvin

But isn't dere a way to check if the user's exist without posting d form . becos u can actually if a user exists server side without using ajax .wanted a client side script to achieve this

- Mike


I have no idea what you are asking. Did your cat walk across the keyboard as you were typing?

- Gautam

Thank you for this post Mike!

But ii have a doubt reg starter site, u said it doesn't check for duplicate user name. But I checked it does. Before adding the user, it queries the database to chk for user(email) ..
If user == null, then only it proceeds otherwise it says "user exists'

- Mike


As far as I can remember, the first version of the site didn't, but the current one does.

- Gautam

Hi Mike,

In the below line

return (int)db.QueryValue(commandText, username) > 0;

why the (int)... is it type casting? if yes, the why is it required. I removed it and tested, query returns an interger only

- Mike


In this case the cast probably isn't necessary, but Database.QueryValue returns a dynamic type, not an integer. The runtime binder is responsible for choosing an appropriate type.

Recent Comments

Sivu 19/10/2016 08:21
In response to Entity Framework Core TrackGraph For Disconnected Data
Oh that's very very very nice ! Thanks for the write up Mike, much appreciated for the taking the to...

Mark 12/10/2016 16:42
In response to ASP.NET Web Pages vNext or Razor Pages
Although "Web Pages" was removed from the roadmap, has it just been renamed to "Razor Pages"?...

Satyabrata 12/10/2016 09:20
In response to Entity Framework Core TrackGraph For Disconnected Data
Nice article. Please write more articles featuring ASP.Net web pages. Thank you...

Julian 26/09/2016 14:27
In response to Loading ASP.NET Core MVC Views From A Database Or Other Location
Fantastic, many thanks Mike! Had got half way down this road before finding your article - saved...

Abolfazl Roshanzamir 14/09/2016 05:36
In response to Loading ASP.NET Core MVC Views From A Database Or Other Location
Nice article. Thanke you so much ....

cyrus 02/09/2016 15:12
In response to ASP.NET Web Pages vNext or Razor Pages
I've got some news. As Damian stated in this link: “We...

Simon 01/09/2016 08:00
In response to Loading ASP.NET Core MVC Views From A Database Or Other Location
Thanks Mike, nice post and exactly what I was looking for. Like you said, I think I'll opt to the...

dave 20/08/2016 14:57
In response to ASP.NET Web Pages vNext or Razor Pages
Do SimplemembershipProvider in viewpages is supported?...

Steven 18/08/2016 04:40
In response to Entity Framework Code First and Stored Procedures
Can you provide the directives (using statements) you're using for EF7 example?...

yousaid 17/08/2016 22:08
In response to ASP.NET Web Pages vNext or Razor Pages
Increasingly, learning a Microsoft tool is no longer worth the return on investment. Too many tools...