Opposite of [compare(" ")] data annotation in .net?
Solution 1
This is the implementation (server side) of the link that @Sverker84 referred to.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class UnlikeAttribute : ValidationAttribute
{
private const string DefaultErrorMessage = "The value of {0} cannot be the same as the value of the {1}.";
public string OtherProperty { get; private set; }
public UnlikeAttribute(string otherProperty)
: base(DefaultErrorMessage)
{
if (string.IsNullOrEmpty(otherProperty))
{
throw new ArgumentNullException("otherProperty");
}
OtherProperty = otherProperty;
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, name, OtherProperty);
}
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
if (value != null)
{
var otherProperty = validationContext.ObjectInstance.GetType()
.GetProperty(OtherProperty);
var otherPropertyValue = otherProperty
.GetValue(validationContext.ObjectInstance, null);
if (value.Equals(otherPropertyValue))
{
return new ValidationResult(
FormatErrorMessage(validationContext.DisplayName));
}
}
return ValidationResult.Success;
}
}
Usage:
public string UserName { get; set; }
[Unlike("UserName")]
public string AlternateId { get; set; }
Details about this implementation, and how to implement it client-side can be found here:
http://www.devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net-mvc-3-part-2
Solution 2
You can use the [NotEqualTo]
data annotation operator included in MVC Foolproof Validation. I used it right now and it works great!
MVC Foolproof
is an open source library created by @nick-riggs and has a lot of available validators. Besides doing server side validation it also does client side unobtrusive validation.
Full list of built in validators you get out of the box:
Included Operator Validators
[Is]
[EqualTo]
[NotEqualTo]
[GreaterThan]
[LessThan]
[GreaterThanOrEqualTo]
[LessThanOrEqualTo]
Included Required Validators
[RequiredIf]
[RequiredIfNot]
[RequiredIfTrue]
[RequiredIfFalse]
[RequiredIfEmpty]
[RequiredIfNotEmpty]
[RequiredIfRegExMatch]
[RequiredIfNotRegExMatch]
Note: if you plan to use MVC Foolproof
lib and support Localization, make sure you apply the patch I provided here: https://foolproof.codeplex.com/SourceControl/list/patches
Solution 3
The complete code for both server side and client side validation is as follows:
[AttributeUsage(AttributeTargets.Property)]
public class UnlikeAttribute : ValidationAttribute, IClientModelValidator
{
private string DependentProperty { get; }
public UnlikeAttribute(string dependentProperty)
{
if (string.IsNullOrEmpty(dependentProperty))
{
throw new ArgumentNullException(nameof(dependentProperty));
}
DependentProperty = dependentProperty;
}
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
if (value != null)
{
var otherProperty = validationContext.ObjectInstance.GetType().GetProperty(DependentProperty);
var otherPropertyValue = otherProperty.GetValue(validationContext.ObjectInstance, null);
if (value.Equals(otherPropertyValue))
{
return new ValidationResult(ErrorMessage);
}
}
return ValidationResult.Success;
}
public void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, "data-val-unlike", ErrorMessage);
// Added the following code to account for the scenario where the object is deeper in the model's object hierarchy
var idAttribute = context.Attributes["id"];
var lastIndex = idAttribute.LastIndexOf('_');
var prefix = lastIndex > 0 ? idAttribute.Substring(0, lastIndex + 1) : string.Empty;
MergeAttribute(context.Attributes, "data-val-unlike-property", $"{prefix}{DependentProperty}");
}
private void MergeAttribute(IDictionary<string, string> attributes,
string key,
string value)
{
if (attributes.ContainsKey(key))
{
return;
}
attributes.Add(key, value);
}
}
Then include the following in JavaScript:
$.validator.addMethod('unlike',
function (value, element, params) {
var propertyValue = $(params[0]).val();
var dependentPropertyValue = $(params[1]).val();
return propertyValue !== dependentPropertyValue;
});
$.validator.unobtrusive.adapters.add('unlike',
['property'],
function (options) {
var element = $(options.form).find('#' + options.params['property'])[0];
options.rules['unlike'] = [element, options.element];
options.messages['unlike'] = options.message;
});
Usage is as follows:
public int FromId { get; set; }
[Unlike(nameof(FromId), ErrorMessage = "From ID and To ID cannot be the same")]
public int ToId { get; set; }
Solution 4
Use this in your get/set logic:
stringA.Equals(stringB) == false
Solution 5
In addition to solution given by @Eitan K, If you want to use other property's display name instead of other property's name, use this snippet:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class UnlikeAttribute : ValidationAttribute
{
private const string DefaultErrorMessage = "The value of {0} cannot be the same as the value of the {1}.";
public string OtherPropertyDisplayName { get; private set; }
public string OtherProperty { get; private set; }
public UnlikeAttribute(string otherProperty)
: base(DefaultErrorMessage)
{
if (string.IsNullOrEmpty(otherProperty))
{
throw new ArgumentNullException("otherProperty");
}
OtherProperty = otherProperty;
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, name, OtherPropertyDisplayName);
}
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
if (value != null)
{
var otherProperty = validationContext.ObjectInstance.GetType()
.GetProperty(OtherProperty);
var otherPropertyValue = otherProperty
.GetValue(validationContext.ObjectInstance, null);
if (value.Equals(otherPropertyValue))
{
OtherPropertyDisplayName = otherProperty.GetCustomAttribute<DisplayAttribute>().Name;
return new ValidationResult(
FormatErrorMessage(validationContext.DisplayName));
}
}
return ValidationResult.Success;
}
}
RollerCosta
Updated on June 07, 2022Comments
-
RollerCosta about 2 years
What is the opposite/negate of
[Compare(" ")]
data annotation" in ASP.NET?i.e: two properties must hold different values.
public string UserName { get; set; } [Something["UserName"]] public string Password { get; set; }
-
pinki over 4 yearsThanks for posting the complete packet for client and server side. Works great!
-
gbianchi about 2 yearsSince c# 8, the nullable reference types will blow warnings in this code. In that case, you have to ajust the definition of IsValid to: protected override ValidationResult? IsValid(object? value, ValidationContext validationContext). That's the correct definition.