1

I have created an Asp.Net Web Api project and used Individual user accounts. When I am adding users to the table the default system automatically checks if the email address supplied already exists in the table, if so a bad request is thrown otherwise the user can be submitted.

How can I also check if the Phone Number is unique and hasn't already been submitted to the table?

// POST api/Account/Register
        [AllowAnonymous]
        [Route("Register")]
        public async Task<IHttpActionResult> Register(RegisterBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            **using (ApplicationDbContext db = new ApplicationDbContext())
            {
                var foundPhoneNumber = await db.Users.FirstOrDefaultAsync(x => x.PhoneNumber.Equals(model.PhoneNumber));

                if (foundPhoneNumber != null)
                {
                    return BadRequest("Phone number already exists");
                }
            }**

            var user = new ApplicationUser()
            {
                UserName = model.Email,
                Email = model.Email,
                PhoneNumber = model.PhoneNumber,
                FirstName = model.FirstName,
                LastName = model.LastName,
                MemberNumber = model.MemberNumber,
                CarReg = model.CarReg
            };

            IdentityResult result = await UserManager.CreateAsync(user, model.Password);

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

I have queried the database to check if there is a Phone Number with the same number. This works, but is there a better way to do this?

Craig Martin
  • 179
  • 2
  • 15
  • What if two people share the same phone number? You know that's a realistic scenario, right? – mason Sep 16 '19 at 18:28
  • Yes, but in this scenario and example, I want to validate against that. For example, what if I had another number such as an enrollment number that must be unique. Is there a better way or more obvious way that I don't know about to perform the check-in ASP.NET Web Api – Craig Martin Sep 16 '19 at 18:31
  • I think what you're doing is fine. But if you want a more generic way refer to this question for a handy extension method https://stackoverflow.com/a/31162909/5431968 – mmohammad Sep 16 '19 at 18:34
  • Possible duplicate of [Entity Framework Add if not exist without update](https://stackoverflow.com/questions/31162576/entity-framework-add-if-not-exist-without-update) – mmohammad Sep 16 '19 at 18:36
  • I'm not trying to add something to the database. A user enters there details in a form if detail X already exists then the data isn't submitted and they are told on the form. – Craig Martin Sep 16 '19 at 18:39
  • Instead of _FirstOrDefault()_ you should use _Any()_ except you really need the returned data. That's because _Any()_ could be better optimized than _FirstOrDefault()_. It does not need to return data other than a boolean value – Daniel Schmid Sep 16 '19 at 19:30
  • I'll make that change, thank you – Craig Martin Sep 16 '19 at 19:35
  • Possible duplicate of [Compare phone numbers without considering any format in Linq to entities and check performance as well](https://stackoverflow.com/questions/23751319/compare-phone-numbers-without-considering-any-format-in-linq-to-entities-and-che) – Andrei Dragotoniu Sep 18 '19 at 09:42
  • I would do a custom validation attribute using something like in the duplicate question linked above – Andrei Dragotoniu Sep 18 '19 at 09:42

3 Answers3

3

Modify your ApplicationUser call and add the following attributes.

public class ApplicationUser : IdentityUser
{
    [MaxLength(17)]
    [IsUnique]
    public string PhoneNumber { get; set; }
}
awais
  • 492
  • 4
  • 17
  • this isn't going to work, phone numbers are notorious hard to check, they can include country codes, spaces, dashes etc. 07564111111 can also be 07564 111111 or 07564 111 111 or 07564-111-111 or +4407564111111 and I can go on like this forever – Andrei Dragotoniu Sep 18 '19 at 09:39
1

You can override ValidateEntity method in ApplicationUserDbContext class, it will trigger on SaveChanges method.

protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
        {
            if (entityEntry != null && entityEntry.State == EntityState.Added)
            {
                var errors = new List<DbValidationError>();
                ////User Validation
                if (entityEntry.Entity is ApplicationUser user)
                {
                    if (this.Users.Any(u => string.Equals(u.PhoneNumber, user.PhoneNumber)))
                    {
                        errors.Add(new DbValidationError("User",
                          string.Format($"Phonenumber {user.PhoneNumber} is already taken")));
                    }
                }

                if (errors.Any())
                {
                    return new DbEntityValidationResult(entityEntry, errors);
                }
            }
            return new DbEntityValidationResult(entityEntry, new List<DbValidationError>());
        }
awais
  • 492
  • 4
  • 17
0

Validation can be added via a custom ValidationAttribute that you add to the PhoneNumber property on you model. Here is a simple example:

   [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
   public class NotABananaAttribute : ValidationAttribute
   {
    public override bool IsValid(object value)
    {
        var inputValue = value as string;
        var isValid = true;

        if (!string.IsNullOrEmpty(inputValue))
        {
            isValid = inputValue.ToUpperInvariant() != "BANANA";
        }

        return isValid;
    }
   }

And its used liked this...

public class Model
{
    [NotABanana(ErrorMessage = "Bananas are not allowed.")]
    public string FavoriteFruit { get; set; }
}

Example sourced from: https://riptutorial.com/csharp/example/18486/creating-a-custom-validation-attribute

Stephen McDowell
  • 839
  • 9
  • 21