Search code examples
c#asp.net-core.net-coreasp.net-core-webapivalidationattribute

.NET Core - How to solve email aready exist when updating data with the same email


I am trying to make an API using MongoDB and .NET Core. But I face a problem while updating the value. I wrote a custom validation like this:

public class EmailUserUniqueAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        UserService? _context = validationContext.GetService(typeof(UserService)) as UserService;
        var entity = _context?.Users().Find(x => x.Email == value.ToString()).FirstOrDefault();

        if (entity != null)
        {
            return new ValidationResult(GetErrorMessage(value.ToString()));
        }

        return ValidationResult.Success;
    }

    public string GetErrorMessage(string email)
    {
        return $"Email {email} is already in use.";
    }
}

I created a custom DTO for updating user data like this:

public class UpdateUserRequestDto
{
    [Required]
    public string UserName { get; set; }
    [Required,DataType(DataType.EmailAddress),EmailUserUnique]
    public string Email { get; set; }
    [Required, MinimumAgeValidator(18)]
    public DateTime DateOfBirth { get; set; }
}

To create a new user, it is working fine. But while updating the values, it is working only when the Email value changed. But when I submitted an update with the same email, then it shows a validation error.

How can I solve this?


Solution

  • As discussed in the comment, you need a unique value such as ID to determine that the current (to-be-updated) document should be excluded in the searching of the documents with a duplicate email address.

    Assume that the UserName is unique,

    In EmailUserUniqueAttribute you need:

    1. Get the value of UserName property from the instance from validationContext.
    2. Search the records/document with the same Email but doesn't have the same UserName (Exclude current document).
    public class EmailUserUniqueAttribute : ValidationAttribute
    {
        #nullable enable
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var usernameProperty = validationContext.ObjectType.GetProperty("UserName");
            var usernameValue = usernameProperty.GetValue(validationContext.ObjectInstance);
                    
            UserService? _context = validationContext.GetService(typeof(UserService)) as UserService;
            var entity = _context?.Users().FirstOrDefault(x => x.Email == value.ToString()
                && x.UserName != usernameValue);
                
            if (entity != null)
            {
                return new ValidationResult(GetErrorMessage(value.ToString()));
            }
    
            return ValidationResult.Success;
        }
        #nullable disable
    
        ...
    }
    

    Sample .NET Fiddle Demo