Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data validation attribute for a condition between two properties asp.net mvc

I want to put a rule between two properties that is one property have to be greater than the other. So what is the data validation attribute that can let me do this ?

Here are my properties

  public int Min{get;set;}
  public int Max{get;set;} 

As you can easily understand Max have to be greater than Min.

Thank you for your help!

like image 376
intern Avatar asked Sep 05 '14 09:09

intern


People also ask

How do you validate model data using DataAnnotations attributes?

ComponentModel. DataAnnotations namespace includes the following validator attributes: Range – Enables you to validate whether the value of a property falls between a specified range of values. RegularExpression – Enables you to validate whether the value of a property matches a specified regular expression pattern.

What is data annotation validator attributes in MVC?

In ASP.NET MVC, Data Annotation is used for data validation for developing web-based applications. We can quickly apply validation with the help of data annotation attribute classes over model classes.


3 Answers

Data validations on your object strike me as a good thing (as well as using client side validation).

This is an attribute that you can use to do what you are asking (which will be able to compare pairs of types that implement IComparable)

public class GreaterThanAttribute : ValidationAttribute
{

    public GreaterThanAttribute(string otherProperty)
        : base("{0} must be greater than {1}")
    {
        OtherProperty = otherProperty;
    }

    public string OtherProperty { get; set; }

    public string FormatErrorMessage(string name, string otherName)
    {
        return string.Format(ErrorMessageString, name, otherName);
    }

    protected override ValidationResult
        IsValid(object firstValue, ValidationContext validationContext)
    {
        var firstComparable = firstValue as IComparable;
        var secondComparable = GetSecondComparable(validationContext);

        if (firstComparable != null && secondComparable != null)
        {
            if (firstComparable.CompareTo(secondComparable) < 1)
            {
                object obj = validationContext.ObjectInstance;
                var thing = obj.GetType().GetProperty(OtherProperty);
                var displayName = (DisplayAttribute)Attribute.GetCustomAttribute(thing, typeof(DisplayAttribute));

                return new ValidationResult(
                    FormatErrorMessage(validationContext.DisplayName, displayName.GetName()));
            }
        }

        return ValidationResult.Success;
    }

    protected IComparable GetSecondComparable(
        ValidationContext validationContext)
    {
        var propertyInfo = validationContext
                              .ObjectType
                              .GetProperty(OtherProperty);
        if (propertyInfo != null)
        {
            var secondValue = propertyInfo.GetValue(
                validationContext.ObjectInstance, null);
            return secondValue as IComparable;
        }
        return null;
    }
}

You can then decorate your model:

  public int Min{get;set;}

  [GreaterThan("Min")]
  public int Max{get;set;}

This is a useful question regarding less than validations MVC custom validation: compare two dates but applies to dates rather than integers but the same approach applies

like image 195
AlexC Avatar answered Sep 20 '22 11:09

AlexC


You could use a Attribute or your view model could implement IValidatableObject. What's nice is that the asp.net mvc modelbinder will automatically run this on post.

public class TestCompareModel : IValidatableObject
{
    [Required]
    public Int32 Low { get; set; }

    [Required]
    public Int32 High { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var results = new List<ValidationResult>();

        if (High < Low)
            results.Add(new ValidationResult("High cannot be less than low"));

        return results;
    }
}

Controller action:

    [HttpPost]
    public ActionResult Test(TestCompareModel viewModel)
    {
        if (!ModelState.IsValid)
            return View(viewModel);

        return RedirectToAction("Index");
    }

View

@model Scratch.Web.Models.TestCompareModel

@{
    ViewBag.Title = "Test";
}

<h2>Test</h2>

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>TestCompareModel</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.Low, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Low, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Low, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.High, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.High, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.High, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>
like image 36
Fran Avatar answered Sep 24 '22 11:09

Fran


I agree with Exception, JQuery is much easier to work with than the model itself for accomplishing this kind of functionality. However that being said with no experience in Javascript/Jquery its worth having a look at the documentation for JQuery here.

You will also find great tutorials here

And the most important part, the actual JQuery library file here. You can download the file and include it in your solution OR simply include a link to a server hosted CDN version of the file in the header of your view. (both options have instructions provided on the link I gave you)

An update to Exceptions answer however, you do not include the functionality required to only allow integer values in the input controls. To fix this simply change the inputs type attribute to "number" like this.

<input type="number" id="Max" name="Max"  />

And modify the Script to remove parsing of String to Integer like this:

$("#Max").focusout(function(){
      if( $(this).val() < $("#Min").val() )
      {
         $("#errormess").html('Max value cannot be lower then min Value');
      }
      else{ $("#errormess").html(''); }
   });

   $("#Min").focusout(function(){
      if( $(this).val() >= $("#Max").val() )
      {
         $("#errormess").html('Max value cannot be lower then min Value');
      }
      else{ $("#errormess").html(''); }
   });
like image 35
Master Yoda Avatar answered Sep 21 '22 11:09

Master Yoda