Validation Report

May 10, 2012 at 11:36 PM

Hi,

Seems like the ValidationReport does not return the error messages for the children in an object graph. I am using a very similar example as your Club and Member example. The validation fails and result is False however when looping through the Errors (as in your above code) the child error is not returned.

 

Is it a bug or I am missing something?

 

thx

Coordinator
May 11, 2012 at 8:01 AM

It is possible that this happens because there is no error messages defined for that rule failure. Could you post the code used to define your rules, and when you iterate through the errors?

The stable release will have default error messages - instead of returning null when no error messages are defined.

May 11, 2012 at 11:30 AM
Edited May 11, 2012 at 11:32 AM

Well my child object has validation message defined. Here is the whole test code:

 

class Program
    {
        static void Main(string[] args)
        {
            NewUserRegistrationDTO dto = new NewUserRegistrationDTO();
            dto.UserName = "Maria";
            dto.Password = "xyz";
            dto.ConfirmPassword = "xyz";
            dto.Email = "xyz@gmail.com";
            dto.Addresses = new List<Address>()
                                {
                                    new Address() {AddressLine1 = "line 1", AddressLine2 = "", PostCode = ""}
                                };

            NewUserRegistrationBO bo = new NewUserRegistrationBO();
            bo.Save(dto);

            Console.ReadLine();
        }
    }

    public class NewUserRegistrationBO
    {
        private Engine _Engine;

        public NewUserRegistrationBO()
        {
            SetUpRules();
        }

        private void SetUpRules()
        {
            _Engine = new Engine();

            _Engine.For<NewUserRegistrationDTO>()
                .Setup(user => user.UserName)
                    .MustNotBeNullOrEmpty()
                    .WithMessage("User name must be provided.")
                .Setup(user => user.Password)   // Field validation with error message
                    .MustNotBeNullOrEmpty()
                    .WithMessage("Password must be provided.")
                .Setup(user => user.ConfirmPassword)
                    .MustNotBeNullOrEmpty()     // Cross Field validation
                    .WithMessage("Confirm password must be provided.")
                    .MustEqual(user => user.Password)
                    .WithMessage("Password and Confirm Password must be same.")
                .Setup(user => user.Email)      // Regex validation
                    .MustMatchRegex(@"^[a-z]+@[a-z]+(\.[a-z]+)*$")
                    .WithMessage("Please provide a valid email address.")
                .Setup(user => user.Addresses)  // Call validate for object graph
                    .MustNotBeNull()
                    .CallValidateForEachElement()
                ;

            _Engine.For<Address>() //child element
                .Setup(add => add.AddressLine1)
                    .MustNotBeNullOrEmpty()
                .Setup(add => add.AddressLine2)
                    .MustNotBeNullOrEmpty()
                    .WithMessage("Address line 2 is mandatory.");


        }

        
        public void Save(NewUserRegistrationDTO dto)
        {
            if (_Engine.Validate(dto))
                Console.WriteLine("DTO is valid");
            else
            {
                Console.WriteLine("DTO is NOT valid");
                ReportValidationErrors(dto);
            }
        }

        private void ReportValidationErrors(NewUserRegistrationDTO dto)
        {
            var report = new ValidationReport(_Engine);
            var result = report.Validate(dto);
            var errors = report.GetErrorMessages(dto);
            foreach (var error in errors)
                Console.WriteLine(error);
            
            // even adding this does not work???
            var childResult = report.Validate(dto.Addresses);
            var childErrors = report.GetErrorMessages(dto.Addresses);
            foreach (var error in childErrors)
                Console.WriteLine(error);

        }
    }

    public class NewUserRegistrationDTO
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string ConfirmPassword { get; set; }
        public string Email { get; set; }
        public List<Address> Addresses { get; set; }
    }

    public class Address
    {
        public string AddressLine1 { get; set; }
        public string AddressLine2 { get; set; }
        public string PostCode { get; set; }
    }

 

class Program
    {
        static void Main(string[] args)
        {
            NewUserRegistrationDTO dto = new NewUserRegistrationDTO();
            dto.UserName = "Maria";
            dto.Password = "xyz";
            dto.ConfirmPassword = "xyz";
            dto.Email = "xyz@gmail.com";
            dto.Addresses = new List<Address>()
                                {
                                    new Address() {AddressLine1 = "line 1", AddressLine2 = "", PostCode = ""}
                                };
            NewUserRegistrationBO bo = new NewUserRegistrationBO();
            bo.Save(dto);
            Console.ReadLine();
        }
    }
    public class NewUserRegistrationBO
    {
        private Engine _Engine;
        public NewUserRegistrationBO()
        {
            SetUpRules();
        }
        private void SetUpRules()
        {
            _Engine = new Engine();
            _Engine.For<NewUserRegistrationDTO>()
                .Setup(user => user.UserName)
                    .MustNotBeNullOrEmpty()
                    .WithMessage("User name must be provided.")
                .Setup(user => user.Password)   // Field validation with error message
                    .MustNotBeNullOrEmpty()
                    .WithMessage("Password must be provided.")
                .Setup(user => user.ConfirmPassword)
                    .MustNotBeNullOrEmpty()     // Cross Field validation
                    .WithMessage("Confirm password must be provided.")
                    .MustEqual(user => user.Password)
                    .WithMessage("Password and Confirm Password must be same.")
                .Setup(user => user.Email)      // Regex validation
                    .MustMatchRegex(@"^[a-z]+@[a-z]+(\.[a-z]+)*$")
                    .WithMessage("Please provide a valid email address.")
                .Setup(user => user.Addresses)  // Call validate for object graph
                    .MustNotBeNull()
                    .CallValidateForEachElement()
                ;
            _Engine.For<Address>() //child element
                .Setup(add => add.AddressLine1)
                    .MustNotBeNullOrEmpty()
                .Setup(add => add.AddressLine2)
                    .MustNotBeNullOrEmpty()
                    .WithMessage("Address line 2 is mandatory.");
        }
        
        public void Save(NewUserRegistrationDTO dto)
        {
            if (_Engine.Validate(dto))
                Console.WriteLine("DTO is valid");
            else
            {
                Console.WriteLine("DTO is NOT valid");
                ReportValidationErrors(dto);
            }
        }
        private void ReportValidationErrors(NewUserRegistrationDTO dto)
        {
            var report = new ValidationReport(_Engine);
            var result = report.Validate(dto);
            var errors = report.GetErrorMessages(dto);
            foreach (var error in errors)
                Console.WriteLine(error);
            
            // even adding this does not work???
            var childResult = report.Validate(dto.Addresses);
            var childErrors = report.GetErrorMessages(dto.Addresses);
            foreach (var error in childErrors)
                Console.WriteLine(error);
        }
    }
    public class NewUserRegistrationDTO
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string ConfirmPassword { get; set; }
        public string Email { get; set; }
        public List<Address> Addresses { get; set; }
    }
    public class Address
    {
        public string AddressLine1 { get; set; }
        public string AddressLine2 { get; set; }
        public string PostCode { get; set; }
    }
Coordinator
May 12, 2012 at 12:58 AM

I see what your problem is...

report.GetErrorMessages(..) gives you the errors that happened on a single object. Therefore, if the errors occurred on a child object graph, those errors do not belong to the parent, rather to the child itself.

to solve your problem:

Interrogate all the addresses to determine errors on them. I.e.:

private void ReportValidationErrors(NewUserRegistrationDTO dto)
{
    var report = new ValidationReport(_Engine);
    var result = report.Validate(dto);
    var errors = report.GetErrorMessages(dto);
    foreach (var address in dto.Addresses)
    {
        foreach(var error in report.GetErrorMessages(address))
        {
             Console.WriteLine(error);
        }
    }
}   

May 12, 2012 at 5:03 AM

Thanks it worked ,,, 

Though it would have been great to get all error messages via report in one go maybe.