Changing validation range programmatically (MVC3 ASP.NET)

后端 未结 2 1449
我在风中等你
我在风中等你 2021-01-04 10:40

Let\'s say I have this view model:


    public class MyModel
    {
        [Range(0, 999, ErrorMessage = \"Invalid quantity\")]
        public int Quantity { get;         


        
相关标签:
2条回答
  • 2021-01-04 11:15

    Something along the lines of this might be more what your after...

    ViewModel:

    public class ViewModel
    {
        public DateTime MinDate {get; set;}
        public DateTime MaxDate {get; set;}
    
        [DynamicRange("MinDate", "MaxDate", ErrorMessage = "Value must be between {0} and {1}")]
        public DateTime Date{ get; set; }
    }
    

    Library class or elsewhere:

    public class DynamicRange : ValidationAttribute, IClientValidatable
        {
            private readonly string _minPropertyName;
            private readonly string _maxPropertyName;
    
        public DynamicRange(string minPropName, string maxPropName)
        {
            _minPropertyName = minPropName;
            _maxPropertyName = maxPropName;
        }
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var minProperty = validationContext.ObjectType.GetProperty(_minPropertyName);
            var maxProperty = validationContext.ObjectType.GetProperty(_maxPropertyName);
    
            if(minProperty == null)
                return new ValidationResult(string.Format("Unknown property {0}", _minPropertyName));
    
            if (maxProperty == null)
                return new ValidationResult(string.Format("Unknown property {0}", _maxPropertyName));
    
            var minValue = (int) minProperty.GetValue(validationContext.ObjectInstance, null);
            var maxValue = (int) maxProperty.GetValue(validationContext.ObjectInstance, null);
    
            var currentValue = (int) value;
    
            if (currentValue <= minValue || currentValue >= maxValue)
            {
                return new ValidationResult(string.Format(ErrorMessage, minValue, maxValue));
            }
    
            return null;
        }
    
        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
                {
                    ValidationType = "dynamicrange",
                    ErrorMessage = ErrorMessage
                };
    
            rule.ValidationParameters["minvalueproperty"] = _minPropertyName;
            rule.ValidationParameters["maxvalueproperty"] = _maxPropertyName;
            yield return rule;
        }
    

    From: MVC unobtrusive range validation of dynamic values

    0 讨论(0)
  • 2021-01-04 11:28

    I think your best bet might be to implement a custom model binder for your specific Model (MyModel). What you could have is something like this:

    public class MyModel
    {
        public int Quantity { get; set; }
    } // unchanged Model
    
    public class MyViewModel
    {
        public MyModel myModel { get; set; }
        public int QuantityMin { get; set; }
        public int QuantityMax { get; set; }
    }
    

    Then you can set these values, and in your custom model binder you can compare your myModel.Quantity property to the QuantityMin and QuantityMax properties.


    Example

    Model:

    public class QuantityModel
    {
        public int Quantity { get; set; }
    }
    

    ViewMode:

    public class QuantityViewModel
    {
        public QuantityModel quantityModel { get; set; }
        public int QuantityMin { get; set; }
        public int QuantityMax { get; set; }
    }
    

    Custom Model Binder:

    public class VarQuantity : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            int MinValue = Convert.ToInt32(bindingContext.ValueProvider.GetValue("QuantityMin").AttemptedValue);
            int MaxValue = Convert.ToInt32(bindingContext.ValueProvider.GetValue("QuantityMax").AttemptedValue);
            int QuantityValue = Convert.ToInt32(bindingContext.ValueProvider.GetValue("quantityModel.Quantity").AttemptedValue);
    
            if (!(QuantityValue >= MinValue && QuantityValue <= MaxValue))
                bindingContext.ModelState.AddModelError("Quantity", "Quantity not between values");
    
            return bindingContext.Model;
        }
    }
    

    Register Custom Model Binder:

    ModelBinders.Binders.Add(typeof(QuantityViewModel), new VarQuantity());
    

    Test Controller Action Methods:

        public ActionResult Quantity()
        {
            return View();
        }
    
        [HttpPost]
        public string Quantity(QuantityViewModel qvm)
        {
            if (ModelState.IsValid)
                return "Valid!";
            else
                return "Invalid!";
        }
    

    Test View Code:

    @model MvcTest.Models.QuantityViewModel
    
    <h2>Quantity</h2>
    
    @using (Html.BeginForm())
    {
        @Html.Label("Enter Your Quantity: ")
        @Html.TextBoxFor(m => m.quantityModel.Quantity)
        <br />
        @Html.Label("Quantity Minimum: ")
        @Html.TextBoxFor(m => m.QuantityMin)
        <br />
        @Html.Label("Quantity Maximum: ")
        @Html.TextBoxFor(m => m.QuantityMax)
        <br /><br />
        <input type="submit" value="Submit" />
    }
    
    0 讨论(0)
提交回复
热议问题