I just came across the CustomValidation attribute in DataAnnotations. After playing with it, I began to like it more than using any of the other, more specific ones.
Just as I try to write rich domain entities, it occurred to me that I might want to also write richer view models, putting validation logic where it belongs.
Of course, the specialized attributes are nice, but it gets real cumbersome if you want to use localized resources for every one, or need to customize something.
If you aren’t familiar with it, here’s how it works. This is my usual AccountLogoutModel which is used with Logout action. It requires that the action be confirmed before proceeding.
using System.ComponentModel.DataAnnotations;
namespace Sample.Models
{
public class AccountLogoutModel
{
[CustomValidation(typeof(AccountLogoutModel), "ValidateConfirmed")]
public bool Confirmed { get; set; }
public static ValidationResult ValidateConfirmed(bool value)
{
if (value != true)
return new ValidationResult(Resources.Phrases.ActionUnconfirmed, new[] { "Confirmed" });
// you could use a string, string.Format, or a localized resource here.
return ValidationResult.Success;
}
}
}
You can also define the methods to take a ValidationContext as a second parameter if you need more control.
Now, just as busines logic resides within entities, your validation logic resides within models.
Drew out.