In my previous post I mentioned that I believe that validation logic should live in the business layer
rather then in the UI. I went as far as to say you should have the rules for validation defined in one place, your business layer, and have your other layers use those rules to apply the validation as necessary. I’ve decided to write a series of posts on how I’ve implemented such a setup in my custom .net framework (I need a cool name for it like “Rails” or something
). In this post I’m going to quickly show how I define validation rules in my business layer and talk through how I then use those rules within the UI. In future posts I’ll dig into more specifics of what the code actually looks like to apply the rules in the UI. Let’s take a look at a sample entity object:
public class Role : EntityObject {
public Role() : base() { }
public Role(int id) : base(id) { }
[Persist, Required, MaxLength(50)]
public string Name {
get { return _name; }
set {
SetDirty(true);
_name = value;
}
}
[Persist, MaxLength(250)]
public string Description {
get { return _description; }
set {
SetDirty(true);
_description = value;
}
}
[Persist, Required]
public int SiteID {
get { return _siteID; }
set {
SetDirty(true);
_siteID = value;
}
}
string _name = String.Empty;
string _description = String.Empty;
int _siteID = -1;
}
As you can see this is a simple Role entity that contains a Name, Descriptions, and SiteId. Within my framework I define many of the rules for how an object should be treated using a set of custom attributes. The [Persist] attribute tells the underlying framework that when .Save() is called on a role instance that particular property should be persisted to the backend data store.
From a validation perspective we can see two custom attributes that define some validation rules for the Role object. The [Required] attribute specifies what properties require a value to be set, and the [MaxLength] attribute defines the maximum length for the name and description property.
Every time a Save() is called on a role object the persistence layer will ensure that a Name, and SiteID is provided and that the lengths of the Name and Description properties are shorter then 50 and 250 characters.
The second piece of the equation is getting the rules defined via these custom attributes applied when people are entering roles into the EditRoles.aspx page. The easiest solution would be to drop a couple RequiredFieldValidator controls on the page as well as set a maximum length on the textboxes that users enter the name and description into. But what happens when my rules change? What happens when I decide that description should also be required, or when I adjust the name field to be 100 characters rather then 50.
If the validation rules where defined in both the business layer and UI layer I’d have more then one place to update my validation rules. Those of you familiar with the DRY principle know that this is far from ideal.
Instead what I’ve done in my framework is applied the validation rules defined on my business object to my UI. One of the wonderful things about ASP.NET is that you can add and remove controls from pages at runtime. What this allows me to do is dynamically inject required field validators into my ASP.NET page at runtime by inspecting the rules defined on my Role entity. This keeps the rules defined in one place and helps me to sleep better at night knowing that nobody is going to get a Role into my system without a name. What a relief! 