Tag Archives: Simple.Validation
Simple.Validation 0.6.1 Released

What’s new?

Testability has been kind of an issue for us with code that relies on the static Validator class. To improve the situation, I added IValidationEngine as an alternative. Validator is still fully backwards compatible

  • Addition of the IValidationEngine interface
  • The DefaultValidationEngine requires an instance of IValidatorProvider for its constructor
  • Validator.SetValidatorProvider() has been marked obsolete. You can still use it, but it will have the side-effect of over-setting Validator.ValidationEngine to a new instance of DefaultValidationEngine.
  • Added a NinjectModule to Simple.Validation.Ninject that configures the DefaultValidationEngine and DefaultValidatorProvider automatically.
Simple.Validation 0.5.0 Released

New Feature

Message() method has been overloaded to accept a function to build the validation message while the object/property is being validated.

Example:

var validator = Properties<Employee>
    .For(e => e.FirstName)
    .Required()
    .Message((context, value) =>
        {
             customMessage = string.Format("Custom Message format '{0}'", value);
             return customMessage;
        });
Simple.Validation 0.4.0–Release Notes

New Features

Added an assertion api to the PropertyValidator so that the Properties<T> api can be extended by clients.

The order of operations for the Properties api is as follows: If(), Required(), Assertions().

As an example, customized support for boolean properties was added to the library using the following code:

    public static class BooleanPropertyExtensions
    {
        public static PropertyValidator<TContext, bool> IsTrue<TContext>(this PropertyValidator<TContext, bool>  self)
        {
            self.Assert((t, p) => p);
            return self;
        }

        public static PropertyValidator<TContext, bool> IsFalse<TContext>(this PropertyValidator<TContext, bool> self)
        {
            self.Assert((t, p) => !p);
            return self;
        }

        public static PropertyValidator<TContext, bool?> IsTrue<TContext>(this PropertyValidator<TContext, bool?> self)
        {
            self.Assert((t, p) => p.GetValueOrDefault());
            return self;
        }

        public static PropertyValidator<TContext, bool?> IsFalse<TContext>(this PropertyValidator<TContext, bool?> self)
        {
            self.Assert((t, p) => p.HasValue && !p.Value);
            return self;
        } 
    }

 

Breaking Changes

RangePropertyValidator has been removed. It’s functionality is still available, but it has been entirely replaced by extension methods that use the new Assert() method on the PropertyValidator.

ValidationResultTypes have been completely removed. Then intent for ValidationResult.Type is that it is custom per project.

What’s new in Simple.Validation 0.3.1?

Silverlight 4

The entire Simple.Validation library has been compiled for Silverlight and included in the NuGet package.

Conditional Property Validators

An If() method has been applied to the following property validators:

When If() is called with the required Predicate, the validator will only apply when the condition specified by the Predicate is met.

        [Test]
        public void If_PredicateIsFalse_ShouldNotValidate()
        {
            // Arrange
            var validator = Properties<Employee>
                .For(e => e.Age)
                .GreaterThanOrEqualTo(18)
                .If(e => e.Age != -1)
                ;

            // Act
            var employee = new Employee()
            {
                Age = -1
            };
            var results = validator.Validate(employee);

            // Assert
            Assert.That(results, Is.Empty);

        }
Simple.Validation v0.2.3

A new release of Simple.Validation is available on NuGet.

The changes include:

While Simple.Data is not intended to focus on property-level validation so much that more complex validation scenarios are difficult, it must be recognized that property-level validation accounts for a large part of validation scenarios. In keeping with the goal of simplicity, Simple.Validation provides some mechanisms for wiring up property-level validations quickly. The Fluent Properties API provides factory methods for creating validators for common property types. When used in conjunction with the CompositeValidator<T> it is a trivial task to get simple property-level validation implemented quickly.

This code is from the Personnel.Sample project included in the source code.

    public class SaveAddressValidator : CompositeValidator<Address>
    {
        public override bool AppliesTo(string rulesSet)
        {
            return rulesSet == RulesSets.Crud.Save;
        }

        protected override IEnumerable<IValidator<Address>> GetInternalValidators()
        {
            yield return Properties<Address>.
                For(a => a.Line1)
                .Length(0, 50)
                .Required()
                .Message("Address Line 1 is required.");

            yield return Properties<Address>
                .For(a => a.Line2)
                .Length(0, 50)
                .NotRequired()
                .Message("Line 2 must be between 0 and 50 characters in length.");

            yield return Properties<Address>
                .For(a => a.Line3)
                .Length(0, 50)
                .NotRequired()
                .Message("Line 3 must be between 0 and 50 characters in length.");

            yield return Properties<Address>
                .For(a => a.PostalCode)
                .Length(0, 20)
                .NotRequired()
                .Message("Postal Code must be between 0 and 20 characters in length.");

            yield return Properties<Address>
                .For(a => a.Country)
                .Length(0, 3)
                .NotRequired()
                .Message("Country must be between 0 and 3 characters in length.");

            yield return Properties<Address>
                .For(a => a.StateOrProvince)
                .Length(0, 50)
                .NotRequired()
                .Message("StateOrProvince must be between 0 and 50 characters in length.");

        } 
    }

 

In this sample, each call to Properties<T>.For() returns an instance of StringPropertyValidator. CompositeValidator will accumulate the results from each of the property-level validators and return them all as a single result set. What about non-string properties?

    public class SaveEmployeeValidator : CompositeValidator<Employee>
    {
        public override bool AppliesTo(string rulesSet)
        {
            return rulesSet == RulesSets.Crud.Save;
        }

        protected override IEnumerable<IValidator<Employee>> GetInternalValidators()
        {
            yield return Properties<Employee>
                .For(e => e.FirstName)
                .Length(3, 50)
                .Required()
                .IgnoreWhiteSpace();

            yield return Properties<Employee>
                .For(e => e.LastName)
                .Length(3, 50)
                .Required()
                .IgnoreWhiteSpace()
                ;

            yield return Properties<Employee>
                .For(e => e.Age)
                .MinValue(18)
                .MaxValue(65)
                ;

            yield return Properties<Employee>
                .For(e => e.Address)
                .Required()
                .Cascade("Save")
                ;

            yield return Properties<Employee>
                .For(e => e.ContactInfo)
                .Required()
                .Count(1)
                .Unique<ContactInfo>(c => c.Type)
                .Cascade("Save");

        }
    }

Employee.Age is of type Int32. Properties<T>.For() any property that is convertible to IComparable will return an instance of RangePropertyValidator. If the property is a reference type, it will return an instance of ReferencePropertyValidator, and if it’s a collection type it will return an instance of EnumerablePropertyValidator.

ReferencePropertyValidator and EnumerablePropertyValidator are similar in that they support Cascading validation onto the reference or collection property itself. This means that Valdiator.Validate<T> will be called for the value of the reference property, or for each element of the collection property. The results will be accumulated into the overall validator results.

When performing cascade validation, there is some question about the type that should be passed to Validator.Validate<T>. Should it be the declared property type (or declared type of the elements of the collection), or should Simple.Validation use the actual type of the property value (or collection element). By default, Cascade() uses the actual type of the property value or collection element, but you can specify the usage of a base type or interface by using the Cascade<T> overload.

In the Personnel.Sample project EmailAddress inherits ContactInfo. There is an EmailAddressValidator that tests the email address against a regular expression. If an instance of EmailAddress is added to the Employee.ContactInfo collection, should it be validated using the EmailAddressValidator or the ContactInfoValidator? Calling the non-generic Cascade() method will cause it to be validated using EmailAddressValdiator. Calling Cascade<ContactInfo>() will cause it to be validated only by the SaveContactInfoValidator.

Announcing Simple.Validation

My company has graciously allowed me to develop a lightweight validation framework and publish it as open-source. There are other very nice validation frameworks available, so why another one? I wanted to be able to use something with all of the strengths and none of the weaknesses of the existing libraries. Here are my stated goals for the project:

  • Simplicity
  • Get moving with a minimum number of moving parts
  • Support dependency injection
  • Focus on object-level validation
  • Support for common property-level validation
  • Support all application types in a consistent manner
  • Support validation at all application layers in a consistent manner
  • Pluggable Architecture

The api I wanted for usage was very simple. Here’s some code from the LoanApplicationSample project:

    public class LoanApplicationDb
    {
        public void Save(LoanApplication loanApplication)
        {
            Validator.Enforce(loanApplication, "Save");
            // do save logic
        }

        public void Submit(LoanApplication loanApplication)
        {
            Validator.Enforce(loanApplication, "Save", "Submit");
            // do submit logic
        }
    }

Just pass your object to the Valdiator.Enforce() method along with the rules sets you wish to validate against and you are off to the races. Enforce will call Validator.Validate(), check for errors, and throw a ValidationException if it finds any. If it doesn’t find any, it just returns the results of Validate(). If you want to bypass the exception logic, just call Validate() directory.

The above code sample demonstrates how to consume the Validator API, but how do you plug into it? You need to be aware of two components. The first is the IValidator<T> implementation. Here is a sample validator that validates the LoanApplciation against the “Save” rules set.

    public class SaveLoanApplicationValidator : IValidator<LoanApplication>
    {
        public bool AppliesTo(string rulesSet)
        {
            return rulesSet == "Save";
        }

        public IEnumerable<ValidationResult> Validate(LoanApplication value)
        {
            var nameResults = Properties<LoanApplication>
                .For(e => e.Name)
                .Required()
                .Length(2, 100)
                .Message("Name is required.")
                .IgnoreWhiteSpace()
                .Validate(value)
                ;

            var reasonResults = Properties<LoanApplication>
                .For(e => e.Reason)
                .Required()
                .Length(10, 500)
                .IgnoreWhiteSpace()
                .Message("Reason is required.")
                .Validate(value)
                ;


            var accumulatedResults = nameResults
                .Concat(reasonResults)
            ;

            return accumulatedResults;
        }
    }

 

This validator uses the built-in PropertyValidator fluent syntax. Use of the built-in validators is entirely optional. They are included as a convenience in order to provide support for common property-level validations. Simple.Validation handles the simple stuff for you Smile. Where many validation frameworks fall down is when there is some kind of complex validation. In Simple.Validation, complex scenarios are handled the same way as property-level validation. Here’s an example:

        public IEnumerable<ValidationResult> Validate(LoanApplication value)
        {
            if (someComplexCondition)
                yield return new ValidationResult()
                                 {
                                     Context = value,
                                     Message = string.Format(messageFormat, arguments),
                                     PropertyName = "PropertyName",
                                     Severity = ValidationResultSeverity.Error,
                                     Type = MyCustomValidationType.SomeComplexConditionError
                                 };

The ValidationResult is a fairly rich object containing a lot of information about the validation error. The Context is the object being validated. You can (and should) provide a detailed message about the error. PropertyName is not required, but will be useful in many scenarios. Severity has levels of Error, Warning, and Informational. ValidationResult.Type is a property there for arbitrary categorization of validation results.

Okay, so now I’ve written a validator—but how does the static Validator class know about the validator I just wrote?

Validator uses an instance of IValidatorProvider to get the list of validators from the simple. Simple.Validation ships with a DefaultValidatorProvider which you can use as follows:

    public class Configuration
    {
        public void ConfigureValidation()
        {
            var validatorProvider = CreateValidatorProvider();
            RegisterValidators(validatorProvider);
            Validator.SetValidatorProvider(validatorProvider);
        }

        private static void RegisterValidators(DefaultValidatorProvider validatorProvider)
        {
            validatorProvider.RegisterValidator(new SaveLoanApplicationValidator());
            validatorProvider.RegisterValidator(new SubmitLoanApplicationValidator());
        }

        private static DefaultValidatorProvider CreateValidatorProvider()
        {
            var validatorProvider = new DefaultValidatorProvider();
            return validatorProvider;
        }
    }

The implementation of DefaultValidatorProvider is naïve, so you are encouraged to use the IValidatorProvider interface as a wrapper around your favorite Dependency Injection framework. We provide a second nuget package called Simple.Validation.Ninject that contains a NinjectValidatorProvider.

We’ve been using Simple.Valdiation internally for awhile and feel pretty good about its release. However, as it hasn’t been published on the public NuGet feed yet, we’re assigning a prelease version of 0.1. We will conform to semantic versioning conventions as outlined in this post from Phil Haack.

So, run Install-Package Simple.Validation from the Visual Studio Package Manager Console and start using the bits! As always, your feedback is much appreciated.

Happy Coding! Open-mouthed smile