I recently had a need to setup validation rules for a registration system. I thought I would share how I was able to create a generic Validator with rules to pass through. Let’s get started.
So I had a rule that an email address couldn’t already exist in the database. So first I needed to define what a rule would look like and this is what I came up with:
public interface IValidationRule<T>
{
bool IsValid(T model);
}
Here is the implementation:
public class EmailAddressDoesNotExistRule : IValidationRule
{
private readonly string _connstring;
public EmailAddressDoesNotExistRule(string connstring)
{
_connstring = connstring;
}
public bool IsValid(User user)
{
using (var db = new DataContext(_connstring))
return !db.EmailAddress.Any(x => x.EmailAddress == user.EmailAddress);
}
}
So now do I pass in an IValidationRule to where I want to validate? No. Do I create an array of IValidationRule in the constructor of what I want to validate? Nope. Do I create an IValidator and pass that in? YEP! Let’s take a look at the IValidator and the implementation.
Here is the interface:
public interface IValidator<T>
{
bool IsValid(T model);
}
Here is the implementation:
public class Validator<TModel, TRule> : IValidator<TModel>
where TRule : IValidationRule<TModel>
{
private readonly TRule[] _validationRules;
public Validator(TRule[] validationRules)
{
_validationRules = validationRules;
}
public bool IsValid(TModel model)
{
var isValid = false;
foreach (TRule rule in _validationRules)
{
if (rule.IsValid(model))
isValid = true;
else
{
isValid = false;
break;
}
}
return isValid;
}
}
If you’re not familiar with .NET generics, you might want to do some research about them. They’re awesome!
Okay, so how do we tie it into our service? Well, we’re going to inject it into the constructor like so:
private readonly IUserValidator _userValidator;
public UserRegistrationService(IUserValidator userValidator)
{
_userValidator = userValidator;
}
I’m sure you’re asking…where did the IUserValidator come from? Well, IUserValidator looks like this:
public interface IUserValidator : IValidator<User>
{
}
Very simple and basically I only do this to make my code more readable. So the implementation of this IUserValidator looks like this:
public class UserValidator : Validator<User, IValidationRule>, IUserValidator
{
public UserValidator(IValidationRule[] validationRules)
: base(validationRules)
{
}
}
So now back in our UserRegistrationService, we have a method that just calls the IsValid on the validator like this:
public void CreateNewRegistration(User user)
{
if (_userValidator.IsValid(user))
//CreateAccountFor(user);
else
//throw new InvalidUserException();
}
Okay, so now for my FAVORITE part of this method for validating…the StructureMap code.
In my DependencyRegistry configure(), I added this code:
ForRequestedType<IUserValidator>()
.TheDefault.Is.OfConcreteType<UserValidator>()
.TheArrayOf<IValidationRule>().Contains(x =>
{
x.OfConcreteType<EmailAddressDoesNotExistRule>()
.WithCtorArg("connstring")
.EqualTo(WebConfig.TeamsConnectionString);
//add more here like the line above
});
So as you add validation rules, you simply add them to your configure() and they’re lined up and ready to go! I’ve also seen this method used with formatting rules. I think it’s pretty awesome!
NOTE: If you have a lot of DB calls for validation, you may want to include some type of loader in the Validator and just pass in the items so you’re not making a ton of DB calls.
Let me know what you think and thanks for reading!