Reputation: 33850
Let's say I have a Person
class with FirstName
and LastName
. I want that the user must enter at least one of the two values in the UI but he may not have to enter each of them.
If I place the Required
attribute / data annotation on each of them, that makes both of them required.
How do I make a server side validation (with client side validation, too) for this rule?
Upvotes: 11
Views: 4371
Reputation: 326
You need validation on both sides: frontend and backend.
Frontend validation should ensure that inputs are correct in order to give the user direct feedback before doing another roundtrip to the server. Here, you need to prevent legit but wrong strings:
On the other hand, "Asdf" is not a name either while "X Æ A-Xii" is a legit name (ask Elon Musk).
Backend validation should then handle concerns of security.
In case you want to only allow instanciation with depending properties, you need to implement the corresponding constructors. If you would end with the same parameter types (here, FirstName and LastName are both type string, so different constructors would not be possible) you provide a constructor with an additional parameter that decides where the input parameter should be assigned to. Furthermore, you only allow private set accessors and provide additional setter methods, if necessary:
public class Person {
public string FirstName { get; private set; } = string.Empty;
public string LastName { get; private set; } = string.Empty;
public Person(string firstName, string lastName) {
FirstName = firstName;
LastName = lastName;
}
public Person(string name, bool nameIsFirstName = false) {
if (nameIsFirstName) {
FirstName = name;
} else {
LastName = name;
}
}
public void UpdateNames(string firstName, string lastName) {
FirstName = firstName;
LastName = lastName;
}
public void UpdateName(string name, bool nameIsFirstName = false) {
if (nameIsFirstName) {
FirstName = name;
} else {
LastName = name;
}
}
}
Furthermore, you should also prevent duplicates:
Upvotes: 0
Reputation: 13419
You could use a custom attribute for this. In short, the custom attribute will retrieve both values and then ensure at least one has a value. See this page for more information. Here is an example (untested code):
[AttributeUsage(AttributeTargets.Property, AllowMultiple =false, Inherited = false)]
public class ValidatePersonName: ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string FirstName = (string)validationContext.ObjectType.GetProperty("FirstName").GetValue(validationContext.ObjectInstance, null);
string LastName = (string)validationContext.ObjectType.GetProperty("LastName").GetValue(validationContext.ObjectInstance, null);
//check at least one has a value
if (string.IsNullOrEmpty(FirstName) && string.IsNullOrEmpty(LastName))
return new ValidationResult("At least one is required!!");
return ValidationResult.Success;
}
}
Usage:
class Person{
[ValidatePersonName]
FirstName{get;set;}
LastName{get;set;}
}
Upvotes: 18