VAAB SelfValidation when using Interfaces, Contracts

Topics: Validation Application Block
Jan 7, 2011 at 3:57 AM

Hi,

For some reason, I can't get my SelfValidation method to fire. After figuring out the other stuff, I thought this would be the easy part. Can anyone suggest what is wrong with the following code?

Interface:

namespace CodeContractsSimple.Interfaces
{
    using System.Diagnostics.Contracts;
    using Contracts;
    using Microsoft.Practices.EnterpriseLibrary.Validation;
    using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
    using Resources;

    [ContractClass(typeof(CustomerContract))]
    public interface ICustomer
    {
        [StringLengthValidator(1, 25, MessageTemplateResourceName = "StringLengthValidator", MessageTemplateResourceType = typeof(ValidationResources))]
        string CompanyName { get; set; }

        [SelfValidation]
        ValidationResults Validate(ValidationResults validationResults);
    }
}

Contract:

namespace CodeContractsSimple.Contracts
{
    using System.Diagnostics.Contracts;
    using Interfaces;
    using Microsoft.Practices.EnterpriseLibrary.Validation;

    [ContractClassFor(typeof(ICustomer))]
    public abstract class CustomerContract : ICustomer
    {
        string ICustomer.CompanyName
        {
            get
            {
                Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>()));

                return default(string);
            }

            set
            {
                Contract.Requires(!string.IsNullOrEmpty(value));
                Contract.Ensures(((ICustomer)this).CompanyName == value);
            }
        }

        ValidationResults ICustomer.Validate(ValidationResults validationResults)
        {
            Contract.Requires(validationResults != null);

            return default(ValidationResults);
        }
    }
}

Object:

namespace CodeContractsSimple
{
    using Interfaces;
    using Microsoft.Practices.EnterpriseLibrary.Validation;
    using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;

    [HasSelfValidation]
    public class Customer : ICustomer
    {
        public string CompanyName { get; set; }

        [SelfValidation]
        public ValidationResults Validate(ValidationResults validationResults)
        {
            if (this.CompanyName == "Bingo!")
            {
                validationResults.AddResult(new ValidationResult("Please enter a sensible company name.", this, null, null, null));
            }

            return validationResults;
        }
    }
}

Client caller:

var validationResults = ValidationFactory
    .CreateValidator<ICustomer>()
    .Validate(customer);

Everything works fine but the self validation never fires. I've no clue where to start.

Many thanks in advance,

Richard

 

Jan 7, 2011 at 6:57 AM

Self validation methods should have no return values so it should be public void Validate(ValidationResults validationResults)

In your case though, this doesn't completely solves the problem.  When you call ValidationFactory.CreateValidator<ICustomer>(), the corresponding validator for the selfvalidation method doesn't get created.  What you can do is either to specify the concreate class in the CreateValidator<T> or if you're using EntLib 5.0,  simply call Validation.Validate rather than creating a validator.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 9, 2011 at 10:59 PM
Edited Jan 9, 2011 at 11:26 PM

You're correct regarding the void return. I don't know how I managed to do that :)

I am using Entlib5.

If I use Validation.Validate(customer) or Validation.Validate<ICustomer>(customer), self validation fires ok but the attributes on the interface will not be picked up and therefore are not validated.

I (preferebly) need both to be picked up. Is this possible?

Richard

Edit: I can do this though:

var validationResults = Validation.Validate(customer);

validationResults.AddAllResults(
    ValidationFactory
    .CreateValidator<ICustomer>()
    .Validate(customer));
Jan 10, 2011 at 8:07 AM

You could put the second line in the Customer class self validation so it'll be cleaner.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 20, 2011 at 6:06 AM

That's what I did as:

[SelfValidation]
public void Validate(ValidationResults validationResults)
{
    validationResults.AddAllResults(
        ValidationFactory
        .CreateValidator<ICustomer>()
        .Validate(this));
}

Now, I have the best of both worlds. If I need complex validation any attributes can't handle, I can add appropriate code to the self validation.

Richard