Data annotation gives some nice possiblity to automate data validation. But I couldn't find an out of the box validation attribute which lets check a member value against another member value.
This is typically required if you have f.ex. from date and to date: The from date shall be smaller (or equal) to the to date. Or to lower-upper-bound ranges: start point shall be smaller (or equal) to end point.
So I created such a validation attribute from scratch. May be you can use it too - at least you can take it as template to create your own validation attribute classes if you need some jump start.
The validation attribute class itself:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Reflection;
using System.Linq;
namespace AnyNamespace
{
/// <summary>
/// Provides functionality to validate member
/// value against other value through comparison
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property,
AllowMultiple = false)]
public sealed class MustCompareToAttribute : ValidationAttribute
{
/// <summary>
/// The comparison operators to fit validation
/// </summary>
public enum Operator
{
/// <summary>
/// The 'smaller' operator
/// </summary>
[Display(Description = "is not smaller than")]
// TODO replace with localized resource
SmallerThan,
/// <summary>
/// The 'smaller or equal' operator
/// </summary>
[Display(Description = "is not smaller than or equal to")]
// TODO replace with localized resource
SmallerOrEqualThan,
/// <summary>
/// The 'greater' operator
/// </summary>
[Display(Description = "is not greater than")]
// TODO replace with localized resource
GreaterThan,
/// <summary>
/// The 'greater or equal' operator
/// </summary>
[Display(Description = "is not greater than or equal to")]
// TODO replace with localized resource
GreaterOrEqualThan
}
/// <summary>
/// The counterpart for value comparison
/// </summary>
public object ComparisonReference { get; }
/// <summary>
/// The operator used for comparison
/// </summary>
public Operator ComparisonAgainstReference { get; }
/// <summary>
/// Gets a value that indicates whether the
/// attribute requires validation context.
/// <c>True</c> if the attribute requires validation context,
/// otherwise <c>false</c>.
/// </summary>
public override bool RequiresValidationContext => true;
/// <summary>
/// Constructor with fixed comparison value and error message
/// </summary>
/// <param name="comparisonReferenceMember">
/// A member name of the validation context's object instance subject
/// to retrieve it's value for comparison
/// </param>
/// <param name="comparisonAgainstReference">
/// The comparison operator which must fullify in order to
/// successfull validate member
/// </param>
/// <param name="errorMessage">
/// The error message to associate with a validation control.
/// The message will be formatted with following values:
/// {0} = Trigger member display name,
/// {1} = Trigger member value,
/// {2} = Comparison operator missmatch text fragment,
/// {3} = Comparsion member display name
/// {4} = Comparsion value,
/// </param>
public MustCompareToAttribute(string comparisonReferenceMember,
Operator comparisonAgainstReference, string errorMessage)
: base(errorMessage)
{
ComparisonAgainstReference = comparisonAgainstReference;
ComparisonReference = comparisonReferenceMember ??
throw new ArgumentNullException(nameof(comparisonReferenceMember));
}
/// <summary>
/// Constructor with fixed comparison value and error message
/// </summary>
/// <param name="comparisonReferenceMember">
/// A member name of the validation context's object
/// instance subject to retrieve it's value for comparison
/// </param>
/// <param name="comparisonAgainstReference">
/// The comparison operator which must fullify in order
/// to successfull validate member
/// </param>
/// <param name="errorMessageAccessor">
/// The function that enables access to validation resources.
/// The message will be formatted with following values:
/// {0} = Trigger member display name,
/// {1} = Trigger member value,
/// {2} = Comparison operator missmatch text fragment,
/// {3} = Comparsion member display name
/// {4} = Comparsion value,
/// </param>
public MustCompareToAttribute(string comparisonReferenceMember,
Operator comparisonAgainstReference, Func<string> errorMessageAccessor)
: base(errorMessageAccessor)
{
ComparisonAgainstReference = comparisonAgainstReference;
ComparisonReference = comparisonReferenceMember ??
throw new ArgumentNullException(nameof(comparisonReferenceMember));
}
/// <summary>
/// Constructor with fixed comparison value and error message
/// </summary>
/// <param name="comparisonReferenceType">
/// The type of the counterpart for value comparison
/// </param>
/// <param name="comparisonReferenceMemberName">
/// A member name of the validation context's object instance subject
/// to retrieve it's value for comparison
/// </param>
/// <param name="comparisonAgainstReference">
/// The comparison operator which must fullify
/// in order to successfull validate member
/// </param>
public MustCompareToAttribute(string comparisonReferenceMemberName,
Operator comparisonAgainstReference) : base((string)null)
{
ComparisonAgainstReference = comparisonAgainstReference;
ComparisonReference = comparisonReferenceMemberName;
}
string ComparisonOperatorText()
{
Type operatorType = typeof(Operator);
return operatorType.GetField(Enum.GetName(operatorType,
ComparisonAgainstReference))
.GetCustomAttribute<DisplayAttribute>().Description;
}
/// <summary>
/// Validates the specified value with respect
/// to the current validation attribute.
/// </summary>
/// <param name="value">
/// The value to validate.
/// </param>
/// <param name="validationContext">
/// The context information about the validation operation.
/// </param>
/// <returns>
/// The validation result
/// </returns>
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
ValidationResult ret = ValidationResult.Success;
if (value != null)
{
var comparisonValue = default(object);
var comparisonMemberDisplayName = default(string);
var comparisonMember = default(MemberInfo);
comparisonMember = validationContext.ObjectType
.GetMember((string)ComparisonReference)
.Where(x => x.MemberType == MemberTypes.Property
|| x.MemberType == MemberTypes.Field)
.FirstOrDefault();
if (comparisonMember == null)
{
throw new MissingMemberException(validationContext.ObjectType.Name,
(string)ComparisonReference);
}
if (comparisonMember is PropertyInfo comparisonPropertyInfo)
{
comparisonValue = comparisonPropertyInfo
.GetValue(validationContext.ObjectInstance);
}
else if (comparisonMember is FieldInfo comparisonFieldInfo)
{
comparisonValue = comparisonFieldInfo
.GetValue(validationContext.ObjectInstance);
}
comparisonMemberDisplayName = comparisonMember.Name;
var attribute = GetCustomAttribute(comparisonMember, typeof(DisplayAttribute));
if (attribute is DisplayAttribute displayAttribute)
{
comparisonMemberDisplayName = displayAttribute.Name;
}
else
{
attribute = GetCustomAttribute(comparisonMember, typeof(DisplayNameAttribute));
if (attribute is DisplayNameAttribute displayNameAttribute)
{
comparisonMemberDisplayName = displayNameAttribute.DisplayName;
}
}
if (comparisonValue != null)
{
int? comparison = null;
if (value is IComparable comparableValue)
{
comparison = comparableValue.CompareTo(comparisonValue);
}
else
{
throw new InvalidOperationException("Trigger member value must implement IComparable");
// TODO replace with localized resource
}
if (comparison <= 0
&& ComparisonAgainstReference == Operator.GreaterThan
|| comparison >= 0
&& ComparisonAgainstReference == Operator.SmallerThan
|| comparison > 0
&& ComparisonAgainstReference == Operator.SmallerOrEqualThan
|| comparison < 0
&& ComparisonAgainstReference == Operator.GreaterOrEqualThan)
{
var memberList = new List<string>() { { validationContext.MemberName } };
memberList.Add(comparisonMember.Name);
var errorMessageString = ErrorMessageString;
if (errorMessageString == null)
{
errorMessageString = "'{0}' ({1}) {2} '{3}' ({4})";
// TODO replace with localized resource
}
ret = new ValidationResult(string.Format(CultureInfo.CurrentCulture,
errorMessageString,
validationContext.DisplayName,
value.ToString(),
ComparisonOperatorText(),
comparisonMemberDisplayName,
comparisonValue.ToString()),
memberList);
}
}
}
return ret;
}
}
}
The usage:
The unit tests (in case you want to adjust the code and make sure all is still working well) :
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace AnyNamespace
{
[TestClass]
public class MustCompareToAttributeTests
{
#region Mock models
class MockModelSmallerThan<T1, T2>
{
[MustCompareTo(nameof(Value2), MustCompareToAttribute.Operator.SmallerThan)]
public T1 Value1 { get; set; }
public T2 Value2 { get; set; }
}
class MockModelSmallerOrEqualThan<T1, T2>
{
[MustCompareTo(nameof(Value2), MustCompareToAttribute.Operator.SmallerOrEqualThan)]
public T1 Value1 { get; set; }
public T2 Value2 { get; set; }
}
class MockModelGreaterThan<T1, T2>
{
[MustCompareTo(nameof(Value2), MustCompareToAttribute.Operator.GreaterThan)]
public T1 Value1 { get; set; }
public T2 Value2 { get; set; }
}
class MockModelGreaterOrEqualThan<T1, T2>
{
[MustCompareTo(nameof(Value2), MustCompareToAttribute.Operator.GreaterOrEqualThan)]
public T1 Value1 { get; set; }
public T2 Value2 { get; set; }
}
class MockModelWrongMemberDeclaration<T1, T2>
{
[MustCompareTo("Typo", MustCompareToAttribute.Operator.GreaterOrEqualThan)]
public T1 Value1 { get; set; }
public T2 Value2 { get; set; }
}
#endregion
#region Wrong usage
[TestMethod]
public void NotCompatible()
{
var model = new MockModelSmallerThan<int, string>()
{
Value1 = 1,
Value2 = "a"
};
// cannot compare integer with string, ArgumentException expected
Assert.ThrowsException<ArgumentException>(() => Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void WrongMemberDeclaration()
{
var model = new MockModelWrongMemberDeclaration<int, string>()
{
Value1 = 1,
Value2 = "a"
};
// cannot retrieve value from member since member declaration is wrong, MissingMemberException expected
Assert.ThrowsException<MissingMemberException>(() => Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void TriggerMemberNotComparable()
{
var model = new MockModelSmallerThan<MockModelSmallerThan<int,int>, MockModelSmallerThan<int, int>>()
{
Value1 = new MockModelSmallerThan<int, int>(),
Value2 = new MockModelSmallerThan<int, int>()
};
// type MockModelSmallerThan<T1, T2> does not implement IComparable
Assert.ThrowsException<InvalidOperationException>(() => Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
#endregion
#region Smaller than
[TestMethod]
public void SmallerThanNullableInt()
{
var model = new MockModelSmallerThan<int?, int?>();
model.Value1 = null;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 1;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = null;
model.Value2 = 2;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 3;
model.Value2 = 3;
// Value1 is not smaller than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 5;
model.Value2 = 4;
// Value1 is not smaller than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 6;
model.Value2 = 7;
// Value1 is smaller than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void SmallerThanMixedInt()
{
var model = new MockModelSmallerThan<int, int?>();
model.Value1 = 100;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 101;
model.Value2 = 101;
// Value1 is not smaller than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 103;
model.Value2 = 102;
// Value1 is not smaller than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 104;
model.Value2 = 105;
// Value1 is smaller than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void SmallerThanStr()
{
var model = new MockModelSmallerThan<string, string>();
model.Value1 = null;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "a";
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = null;
model.Value2 = "a";
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "b";
model.Value2 = "b";
// Value1 is not smaller than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "d";
model.Value2 = "c";
// Value1 is not smaller than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "e";
model.Value2 = "f";
// Value1 is smaller than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
#endregion
#region Smaller or equal than
[TestMethod]
public void SmallerOrEqualThanNullableInt()
{
var model = new MockModelSmallerOrEqualThan<int?, int?>();
model.Value1 = null;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 8;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = null;
model.Value2 = 9;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 10;
model.Value2 = 10;
// Value1 is not smaller or equal than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 12;
model.Value2 = 11;
// Value1 is not smaller or equal than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 13;
model.Value2 = 14;
// Value1 is smaller or equal than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void SmallerOrEqualThanMixedInt()
{
var model = new MockModelSmallerOrEqualThan<int?, int>();
model.Value1 = null;
model.Value2 = 106;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 107;
model.Value2 = 108;
// Value1 is not smaller or equal than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 110;
model.Value2 = 109;
// Value1 is not smaller or equal than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 111;
model.Value2 = 112;
// Value1 is smaller or equal than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void SmallerOrEqualThanStr()
{
var model = new MockModelSmallerOrEqualThan<string, string>();
model.Value1 = null;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "g";
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = null;
model.Value2 = "h";
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "i";
model.Value2 = "i";
// Value1 is not smaller or equal than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "l";
model.Value2 = "k";
// Value1 is not smaller or equal than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "m";
model.Value2 = "n";
// Value1 is smaller or equal than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
#endregion
#region Smaller or equal than
[TestMethod]
public void GreaterThanNullableInt()
{
var model = new MockModelGreaterThan<int?, int?>();
model.Value1 = null;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 15;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = null;
model.Value2 = 16;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 17;
model.Value2 = 17;
// Value1 is not greater than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 19;
model.Value2 = 18;
// Value1 is greater than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 20;
model.Value2 = 21;
// Value1 is not greater than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void GreaterThanMixedInt()
{
var model = new MockModelGreaterThan<int, int?>();
model.Value1 = 113;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 114;
model.Value2 = 114;
// Value1 is not greater than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 116;
model.Value2 = 115;
// Value1 is greater than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 117;
model.Value2 = 118;
// Value1 is not greater than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void GreaterThanStr()
{
var model = new MockModelGreaterThan<string, string>();
model.Value1 = null;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "o";
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = null;
model.Value2 = "p";
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "q";
model.Value2 = "q";
// Value1 is not greater than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "s";
model.Value2 = "r";
// Value1 is greater than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "t";
model.Value2 = "u";
// Value1 is not greater than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
#endregion
#region Greater or equal than
[TestMethod]
public void GreaterOrEqualThanNullableInt()
{
var model = new MockModelGreaterOrEqualThan<int?, int?>();
model.Value1 = null;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 22;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = null;
model.Value2 = 23;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 24;
model.Value2 = 24;
// Value1 is greater or equal than Value2, so NOT OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 26;
model.Value2 = 25;
// Value1 is greater or equal than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 27;
model.Value2 = 28;
// Value1 is not greater or equal than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void GreaterOrEqualThanMixedInt()
{
var model = new MockModelGreaterOrEqualThan<int, int?>();
model.Value1 = 119;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 120;
model.Value2 = 120;
// Value1 is greater or equal than Value2, so NOT OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 122;
model.Value2 = 121;
// Value1 is greater or equal than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = 123;
model.Value2 = 124;
// Value1 is not greater or equal than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
[TestMethod]
public void GreaterOrEqualThanStr()
{
var model = new MockModelGreaterOrEqualThan<string, string>();
model.Value1 = null;
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "v";
model.Value2 = null;
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = null;
model.Value2 = "w";
// null values are not compared, so the validation is OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "x";
model.Value2 = "x";
// Value1 is greater or equal than Value2, so NOT OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "z";
model.Value2 = "y";
// Value1 is greater or equal than Value2, so OK
Assert.IsTrue(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
model.Value1 = "A";
model.Value2 = "B";
// Value1 is not greater or equal than Value2, so NOT OK
Assert.IsFalse(Validator.TryValidateObject(model, new ValidationContext(model), new List<ValidationResult>(), true));
}
#endregion
}
}
Sorry for the missing c# formatting style - this time I wasn't able to copy the code nicely. Last time used Microsoft Word and it worked quite well, but this time I didn't figured out, what is wrong. May be I should restart my PC, since it's running for a while ...