uncategorized

I tried to be EViL today

I know what all of you are thinking  “Oooohhh, this is going to be good.  I better pick up tomorrows Frostbitten Times to see what carnage appears on the front page.”  Sorry to disappoint, but I’m a lover….really….

After seeing a number of different attribute based validation schemes floating around the web, I decided to give one a try.  I came across David Donaldson‘s post a few days ago and decided to give the open source project EViL (Entity Validation Library) a try.

Installation of the product was pretty easy.  Download here and unzip the file.  Add a reference to the EvilAttributes.dll assembly.  Now all you need to do is decorate your POO (plain old objects) and turn them into something special.  The list of available attributes is fairly comprehensive, but I did manage to find a few problems areas.  The following code shows a property that represents an Order Amount.  The business rule that I was trying to implement, as you can see by the message, is that the Amount must be greater than zero.

1
2
3
4
5
6
7
8
private double _amount;

[EvilAttributes.ValidateMinValue(0.01,"Order Amount must be greater than 0")]
public double Amount
{
get { return _amount; }
set { _amount = value; }
}

I couldn’t find a way to do this in EViL and ultimately could only come close by using the value of one cent which isn’t optimal. What EViL needs is an attributes with the following signatures:

1
ValidateGreaterThanMinValue(double minValue, string, message)

The second issue that I have with the framework is that none of the attributes are capable of handling multiple datatypes.  Another scenario that I wanted to use was a validation that required that the number of products on an order is greater than 0.  The total Product count is an integer type (we don’t sell fractional dog sleds here) but the ValidateMinValue attribute only accepts a double as the minimum value parameter.  Again, this is workable, but not optimal.

A few of my final issues with EViL are to do with how you point an attribute at another property for comparison and the use of the same attribute multiple times.  First the property comparison validation.  As you can see in the sample below, identifying the property that is to be used for comparison is done by passing in the property name as a string value.  I’m a strongly typed kinda guy and I’d really rather see that implementation.  Maybe I’m don’t know enough about reflection to understand this isn’t possible, but I know what I’d like in my ideal world.  Another thing that I’d really like to see is the ability for the comparisons to be performed against a private property, field or constant (not so much the constant, but I added it here ‘cause you just never know).  I really don’t like having to create a public property just to be able to compare against a value.

As the example below shows, I really want to be able to compare the Order Date against both the MinimumOrderDate and the Customer object’s SignUpDate.  I can’t.  I’m not allowed to use the ValidateDateOccursOnOrAfter attribute more than once per property.  That sucks.  My experience shows that validation is rarely that simple.  To top it all off, the EViL accepts the Customer.SignUpDate (Customer is a property on the Orders object) as a parameter for the attribute, but it can’t or won’t use the embedded objects for validation.  Again, my experience shows that domains will not always have the values in the domain object that you’re comparing against.

1
2
3
4
5
6
7
8
private DateTime _orderDate;

[EvilAttributes.ValidateDateOccursOnOrAfter("MinimumOrderDate", "Order Date must be on or after today's date")] [EvilAttributes.ValidateDateOccursOnOrAfter("Customer.SignUpDate","Order Date must be on or after the customer's Sign Up Date")]
public DateTime OrderDate
{
get { return _orderDate; }
set { _orderDate = value; }
}

As a v1 product I think that EViL is going in the right direction.  I hope that the guys writing the code take this as constructive criticism.  I really want EViL to be able to do all of these things.  When it does, I’ll be using this in production code.