I have to create a validation system(I don’t want to use Data Annotation or any other system) for my C# application using .Net Compact Framework, where I have an object
which contains many other objects.
Many of the properties are dependent on each other means they have some sort of dependencies.
I can write a simple validator
class which goes through all the properties
and checks them one by one with lots of if and else
but I want to design something dynamic e.g. I should be able to specify list of dependencies on a property and specify a method which should be invoked during validation.
I mean some design guidelines would be appreciated ?
Example ( just for demo purpose ):
public enum Category
{
Toyota,
Mercedes,
Tata,
Maruti
}
class MyBigClass
{
public Category Category { get; set; }
public double LowerPrice { get; set; }
public double UpperPrice { get; set; }
public SomeOtherObject OtherObject { get; set; }
public List<string> Validate()
{
List<string> listErrors = new List<string>();
ParameterInfo pInfo = null;
switch (Category)
{
case Category.Toyota:
pInfo = ParameterStorage.GetParameterInfo(PTYPE.Category_Toyota);
break;
case Category.Mercedes:
pInfo = ParameterStorage.GetParameterInfo(PTYPE.Category_Mercedes);
break;
case Category.Tata:
pInfo = ParameterStorage.GetParameterInfo(PTYPE.Category_Tata);
break;
case Category.Maruti:
pInfo = ParameterStorage.GetParameterInfo(PTYPE.Category_Maruti);
break;
default:
break;
}
if (LowerPrice < pInfo.Min || LowerPrice >= pInfo.Max)
{
listErrors.Add("LowerPrice");
}
if (UpperPrice > pInfo.Max || UpperPrice <= pInfo.Min)
{
listErrors.Add("UpperPrice");
}
return listErrors;
}
}
public enum PTYPE
{
RATING,
Category_Tata,
Category_Toyota,
Category_Mercedes,
Category_Maruti
}
public class ParameterInfo
{
public PTYPE Type { get; set; }
public int Min { get; set; }
public int Max { get; set; }
public int Default { get; set; }
}
public class ParameterStorage
{
private static Dictionary<PTYPE, ParameterInfo> _storage = new Dictionary<PTYPE, ParameterInfo>();
static ParameterStorage()
{
_storage.Add(PTYPE.Category_Maruti, new ParameterInfo { Type = PTYPE.Category_Maruti, Min = 50000, Max = 200000 });
_storage.Add(PTYPE.Category_Mercedes, new ParameterInfo { Type = PTYPE.Category_Mercedes, Min = 50000, Max = 800000 });
_storage.Add(PTYPE.Category_Toyota, new ParameterInfo { Type = PTYPE.Category_Toyota, Min = 50000, Max = 700000 });
_storage.Add(PTYPE.Category_Tata, new ParameterInfo { Type = PTYPE.Category_Tata, Min = 50000, Max = 500000 });
}
public static ParameterInfo GetParameterInfo(PTYPE type)
{
ParameterInfo pInfo = null;
_storage.TryGetValue(type, out pInfo);
return pInfo;
}
}
In the above example I have a MyBigObject
which contains some properties and some other objects and I have a storage
class which keeps all the limits of properties which will be required to validate a property.
As described in the above example I have to get ParameterInfo
for each property and then compare, I am looking for some kind of automatic way/dynamic way of doing the same.
7
- Objects that contain many other objects are probably doing too many things.
- Requiring the programmer to specify dependencies is forcing them to repeat themselves, which will lead to errors/inconsistencies. If you can find a way to detect dependencies (statically or dynamically) that would be better.
- Having a bundle of dependencies makes me concerned that your abstractions are not as clean as they should be. Dependencies between variables should (ideally) be isolated within a class. This might not apply in your case, but as a guideline – be sure you really need that tight coupling between variables in different classes.
And all that said, compact framework has had to do input validation for forever. Even if data annotations aren’t supported, this is likely to be a solved problem.
1
What about extracting the validation, and putting it at the same level as the input?
What I want to say is that it’s not the role of an object to validate itself. An object should always be valid: creating an invalid one doesn’t make too much sense. In the same way, you don’t create a person with an age of -50
, because an age is always a positive value or zero.
In order to ensure an object is valid, one uses Code contracts in .NET Framework. Invariants would be especially useful, since they would not only prevent creating an invalid object, but also alter a valid one so it becomes invalid. In the same way, constraints in databases prevent invalid data from being stored.
Then, finding a place for input validation will depend on the context. If the object is created from user input (including, for example, an application which is using your API), validate the input. Other situations would mitigate the validation somewhere else. If creating an object is a difficult task, one will use a factory, which will how to create an object, without violating its contracts.
0
I think there is one mistake you are making. And that is you want to create a framework/library directly. Eg. you don’t know all cases this framework/library needs to solve, yet, you are trying to create this framework/library.
You should first do things directly, without first making a framework. Only after you create multiple cases should you try to abstract away what is common among those classes. Trying to be “dynamic” and “universal” will only hurt you in the long run.
Also, your code example is screaming from bad OO design. The moment you name an enum “type” or “kind” (or “category” in your case), it becomes obvious it should be multiple different classes within a hierarchy. This is probably why your code looks so bad and “static”. Because you didn’t care about proper separation of concerns and polymorphism. If you did this, you could even realize you don’t need any dynamic validation and that hand-coded validation is just fine.
Well, if you want to get rid of those switch statements it’s a good idea to use polymorphism to validate objects (e.g. making MyBigClass a class which is supertype for your vehicle brands).
The benefits of this approach are:
- You can use dynamic dispatch for methods like validate which are abstract at MyBigClass Level and are implemented in the specific classes (Toyota, Mercedes, …) which extend MyBigClass
- The rules for each vehicle type are encapsulated
You could specify an interface, say IValidatable and use reflection to loop through all the properties and sub properties and validate any which implement the interface. You then only need to implement Validate on each small sub property.
Many of the properties are dependent on each other means they have some sort of dependencies.
This is the root of your problem though. Having something thats hard to validate is just the symptom. Your best best is to split your class into smaller more manageable components.
I think you want something like this Fluent Validator for ASP MVC
The idea is the same as with annotations, but you can define rules at runtime, though with much less “if-statements”.
Here is the sample code of validation method:
[Validator(typeof(PersonValidator))]
public class Person {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
RuleFor(x => x.Id).NotNull();
RuleFor(x => x.Name).Length(0, 10);
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).InclusiveBetween(18, 60);
}
}