3

I have a Model which have both phone number and email in MVC 4. It's something like registration. So user can provide either email or cellphone number or both of them. However I can't make a alternative required field of them. My Model is like

public class RegisterModel
    {
        [Required]
        [Display(Name = "User name")]        
        [UsernameValidator(ErrorMessage = "Only Letters and numbers")]
        [System.Web.Mvc.Remote("IsUserExitst", "Account", HttpMethod = "POST", ErrorMessage = "This user name already exists. Try a new one.")]
        public string UserName { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [System.ComponentModel.DataAnnotations.Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }

        [Required]
        [MaxLength(50)]
        [EmailOrPhoneValidator(ErrorMessage = "Invalid Phone number")]
        [Display(Name = "Phone number")]
        [System.Web.Mvc.Remote("IsMobOrEmailExists", "Account", HttpMethod = "POST", ErrorMessage = "This Phone number or Email already exists. Try a new one.")]
        public string MobileNo { get; set; }


        [Required]
        [MaxLength(50)]
        [EmailAddress(ErrorMessage = "Invalid Email address")]
        [Display(Name = "Email")]
        [System.Web.Mvc.Remote("IsEmailExists", "Account", HttpMethod = "POST", ErrorMessage = "This Email already exists. Try a new one.")]
        public string Email { get; set; }
    }

Here I want to use Email and PhoneNo alternatively. I want to write a class which works as Custom required field. I have gone through this Questions,

  1. Question Here the answer provided a solution combined with javascript. But I won't use it. I will write down the class file and implement my logics here.
  2. RequiredIf is seems the exact suggestion of my question, but I so tired to try that solution. I am not capable to understand how to import the .dll in my project. and it's developed in Mvc 3
  3. Another solution, but here they have combined the alternative properties in a class. So how do I do as my properties are completely separate. So what to do.
Community
  • 1
  • 1
Ananda G
  • 2,389
  • 23
  • 39
  • 1
    What is wrong with the first link - that is exactly what you seem to want. It requires the `MobileNo` to be provided if `Email` is not provided, and `Email` to be provided if `MobileNo` is not provided. I assume in the 2nd option, your referring to a [foolproof](http://foolproof.codeplex.com/) attribute? (which also has a `[RequiredIfNot]`) –  Apr 03 '17 at 05:45
  • I don't prefer `javascript`, because I can't show the error message similarly with the others required errors. Javascript is showing errors in it's own way. – Ananda G Apr 03 '17 at 05:47
  • 1
    Of course you can. That is exactly how client side validation works using `jquery.validate.js` and `jquery.validate.unobtrusive.js` –  Apr 03 '17 at 05:49

1 Answers1

2

I would go with solution 2 and create a RequiredIf validation attribute. No need to import any DLLs since you can just create the class yourself. Here is an example of what the attribute could look like. It's from a RequiredIfTrue attribute I use in my own code and I exchanged the validation logic to look for empty values

public class RequiredIfEmpty : ValidationAttribute
{
    private string _fieldName;

    public RequiredIfEmpty(string fieldName)
    {
        _fieldName = fieldName;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var property = validationContext.ObjectType.GetProperty(_fieldName);
        if (property == null)
        {
            throw new ArgumentException("No property with the name " + _fieldName + " found.");
        }

        string fieldValue = (string)property.GetValue(validationContext.ObjectInstance, null);
        if (String.IsNullOrWhiteSpace(fieldValue))
        {
            return (value != null && !String.IsNullOrWhiteSpace((string)value) ? ValidationResult.Success : new ValidationResult(ErrorMessage));
        }
        else
        {
            return ValidationResult.Success;
        }
    }
}

In your ViewModel you can use the attribute like any other attribute but you have to specify the name of the alternative property

[RequiredIfEmpty("Email", ErrorMessage = "Phone number invalid")]
[MaxLength(50)]
[Display(Name = "Phone number")]
[System.Web.Mvc.Remote("IsMobOrEmailExists", "Account", HttpMethod = "POST", ErrorMessage = "This Phone number or Email already exists. Try a new one.")]
public string MobileNo { get; set; }
mboldt
  • 1,780
  • 11
  • 15
  • You portion of code is working pretty okay. But it is showing a message 2 times if I write `RequiredIfEmpty` above both entity in the validation summary. On the other hand if i write above any of it it is not marking only single input field rather than highlighting both input boxes. – Ananda G Apr 03 '17 at 06:02
  • 2
    This will not give any client side validation. –  Apr 03 '17 at 06:03
  • Yes!! exactly @Stephen Muecke, After form submit it is coming back having the validation errors. – Ananda G Apr 03 '17 at 06:09
  • @lazycoder - That is not client side validation, its server side validation. In order to implement client side validation, the attribute needs to implement `IClientValidatable` and the rules need to be added to the `$.validator` (as per the first link in your question) –  Apr 03 '17 at 06:11
  • Okay. I need to recheck again. Thanks. – Ananda G Apr 03 '17 at 06:12
  • [Sephen Muecke]{http://stackoverflow.com/users/3559349/stephen-muecke} it's working. But the problem is it is showing double required exception. How can I reduce the double exception to single one? I have written for both entities, how to reduce them? If I don't add both of them it is not focusing another required field, just focusing the first / the property applied one only. – Ananda G Apr 03 '17 at 06:37
  • @lazycoder, Sorry I do not understand what your saying. If you have correctly implemented the code, you will only ever get a validation error if neither `MobileNo` or `Email` textboxes are completed (in which case it will show an error message against both textboxes and set focus to the first one) - which is exactly what the expected result should be (I am not sure what your expecting to happen) –  Apr 03 '17 at 06:59
  • @lazycoder I can come up with 2 possible solutions. Either you change the validation attribute to check for both values and then only add the attribute to one of the properties. The downside is that only one form field will receive the error state. Another possibility would be to remove duplicate validation messages in the controller. It's not perfect but should work. See this [link](http://stackoverflow.com/questions/36361095/remove-modelstate-errors-in-asp-net-mvc) for info – mboldt Apr 03 '17 at 08:36