With the help of this blog: http://goneale.com/2009/03/04/using-metadatatype-attribute-with-aspnet-mvc-xval-validation-framework/
I was able to create a method that will test my object based on validations defined by data annotations. It will execute any validation attribute that derives from ValidateAttribute. I can now pass my object to this method from my service layer (or DomainModel) and my service layer is no longer dependent on the controller. This will ensure that validation will always be executed prior to persisting data into the database. I couldn't use the code on the blog as is, as I don't seem to have access to some of the extension methods that Graham was using, so here's my version of it:
public static IList<KeyValuePair<string, string>> GetErrors(object obj)
{
// get the name of the buddy class for obj
MetadataTypeAttribute metadataAttrib = obj.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault() as MetadataTypeAttribute;
// if metadataAttrib is null, then obj doesn't have a buddy class, and in such a case, we'll work with the model class
Type buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : obj.GetType();
var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast<PropertyDescriptor>();
var modelClassProperties = TypeDescriptor.GetProperties(obj.GetType()).Cast<PropertyDescriptor>();
var errors = from buddyProp in buddyClassProperties
join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name // as this is an inner join, it will return only the properties that are in both the buddy and model classes
from attribute in buddyProp.Attributes.OfType<ValidationAttribute>() // get only the attributes of type ValidationAttribute
where !attribute.IsValid(modelProp.GetValue(obj))
select new KeyValuePair<string, string>(buddyProp.Name, attribute.FormatErrorMessage(string.Empty));
return errors.ToList();
}
This code works with both classes that do and don't have buddy classes, although if you don't use buddy classes, this code can be simplified a bit.
I hope you find this useful.