(Enterprise Validation Block, Interfaces) => BIG Trouble
I had a first look at Microsoft’s Enterprise Validation Block 4.1 today and trashed it before I even got really started. The reason: The thing doesn’t really support OO-architectures that rely on interfaces / polymorphism.
I ran my test with this simple interface / implementation:
public interface IModel { [StringLengthValidator(1, 5, MessageTemplate = "First rule failed.")] string First { get; set; } [StringLengthValidator(1, 5, MessageTemplate = "Second rule failed.")] string Second { get; set; } [StringLengthValidator(1, 5, MessageTemplate = "Third rule failed.")] string Third { get; set; } } public class Model : IModel { public string First { get; set; } public string Second { get; set; } public string Third { get; set; } }
Now look at this test:
public void Test() { Model model = new Model(); var result = Validation.Validate(model); foreach (var validationResult in result) { Console.Out.WriteLine(validationResult.Message); } }
The code above won’t output a single validation error, because it only checks the Model class for validation attributes. And there are none – the rules have been declared in the IModel interface. My bad.
The code below, on the other hand, works. Notice that the model variable is declared using the interface type:
public void Test() { IModel model = new Model(); var result = Validation.Validate(model); foreach (var validationResult in result) { Console.Out.WriteLine(validationResult.Message); } }
Now, it gets really ugly when you’re having attributes at different places. After this initial test, I moved the third validation rule into the implementing Model class and removed the Third property from the interface:
public interface IModel { [StringLengthValidator(1, 5, MessageTemplate = "First rule failed.")] string First { get; set; } [StringLengthValidator(1, 5, MessageTemplate = "Second rule failed.")] string Second { get; set; } } public class Model : IModel { public string First { get; set; } public string Second { get; set; } [StringLengthValidator(1, 5, MessageTemplate = "Third rule failed.")] public string Third { get; set; } }
As a result, validating for the IModel interface returns two validation errors, and validating for the Model class reports a single error for the third rule. Now think about handling scenarios where your class implements several interfaces that may provide validation rules. Ouch.
Support for inheritance was the absolute first thing I tested. Frankly, it is beyond me how this library could make it into production over a year ago with this kind of behavior.
This not only promotes bad design, it’s also dangerous as hell because refactoring silently breaks your validation.