How to validate one field related to another's value in ASP .NET MVC 3

前端 未结 3 411
隐瞒了意图╮
隐瞒了意图╮ 2020-11-28 07:40

I had two fields some thing like phone number and mobile number. Some thing like..

    [Required]
    public string Phone { get; set; }

    [Required]
    p         


        
3条回答
  •  清歌不尽
    2020-11-28 08:10

    One possibility is to write a custom validation attribute:

    public class RequiredIfOtherFieldIsNullAttribute : ValidationAttribute, IClientValidatable
    {
        private readonly string _otherProperty;
        public RequiredIfOtherFieldIsNullAttribute(string otherProperty)
        {
            _otherProperty = otherProperty;
        }
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var property = validationContext.ObjectType.GetProperty(_otherProperty);
            if (property == null)
            {
                return new ValidationResult(string.Format(
                    CultureInfo.CurrentCulture, 
                    "Unknown property {0}", 
                    new[] { _otherProperty }
                ));
            }
            var otherPropertyValue = property.GetValue(validationContext.ObjectInstance, null);
    
            if (otherPropertyValue == null || otherPropertyValue as string == string.Empty)
            {
                if (value == null || value as string == string.Empty)
                {
                    return new ValidationResult(string.Format(
                        CultureInfo.CurrentCulture,
                        FormatErrorMessage(validationContext.DisplayName),
                        new[] { _otherProperty }
                    ));
                }
            }
    
            return null;
        }
    
        public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
                ValidationType = "requiredif",
            };
            rule.ValidationParameters.Add("other", _otherProperty);
            yield return rule;
        }
    }
    

    which you would apply to one of the properties of your view model:

    public class MyViewModel
    {
        [RequiredIfOtherFieldIsNull("Mobile")]
        public string Phone { get; set; }
    
        public string Mobile { get; set; }
    }
    

    then you could have a controller:

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(new MyViewModel());
        }
    
        [HttpPost]
        public ActionResult Index(MyViewModel model)
        {
            return View(model);
        }
    }
    

    and finally a view in which you will register an adapter to wire the client side validation for this custom rule:

    @model MyViewModel
    
    
    
    
    
    @using (Html.BeginForm())
    {
        
    @Html.LabelFor(x => x.Phone) @Html.EditorFor(x => x.Phone) @Html.ValidationMessageFor(x => x.Phone)
    @Html.LabelFor(x => x.Mobile) @Html.EditorFor(x => x.Mobile) @Html.ValidationMessageFor(x => x.Mobile)
    }

    Pretty sick stuff for something so extremely easy as validation rule that we encounter in our everyday lives. I don't know what the designers of ASP.NET MVC have been thinking when they decided to pick a declarative approach for validation instead of imperative.

    Anyway, that's why I use FluentValidation.NET instead of data annotations to perform validations on my models. Implementing such simple validation scenarios is implemented in a way that it should be - simple.

提交回复
热议问题