Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Castle validator

Status
Not open for further replies.

whosrdaddy

Vendor
Mar 11, 2003
4,231
BE
Hi I am using Caste Validator in my domain objects.

here's an excerpt of my code

Code:
namespace DCM.Data.Models
{
    public class UserEntity : EntityBase
    {
        [ValidateNonEmpty("RuleNotEmpty, Username")]
        public virtual string Username { get; set; }
        [ValidateNonEmpty]
        public virtual string Password { get; set; }
        [ValidateNonEmpty]
        public virtual string Fullname { get; set; }
        public virtual bool IsDeleted { get; set; }
        public virtual LanguageEntity Language { get; set; }
        public virtual IList<RoleEntity> Roles { get; private set; }

        public UserEntity()
        {
            Roles = new List<RoleEntity>();
        }

        public virtual void Validate()
        {
            var errors = LocalizedCastleValidationRunner.GetErrors(this).ToList();
            errors.AddRange(ValidateNonAdminUser(this));
            if (errors.Any())
                throw new RulesException(errors);
            
        }

        public static IEnumerable<ErrorInfo> ValidateNonAdminUser(UserEntity userEntity)
        {
            if (userEntity.Username.ToLower().Equals("admin"))
                yield return new ErrorInfo("Username", "RuleNonAdmin");
        }
    }
}


I don't like this code 100%.

what I would like to achieve is this:

Code:
namespace DCM.Data.Models
{
    public class UserEntity : EntityBase
    {
        [ValidateNonEmpty("RuleNotEmpty, Username")]
        public virtual string Username { get; set; }
        [ValidateNonEmpty]
        public virtual string Password { get; set; }
        [ValidateNonEmpty]
        public virtual string Fullname { get; set; }
        public virtual bool IsDeleted { get; set; }
        public virtual LanguageEntity Language { get; set; }
        public virtual IList<RoleEntity> Roles { get; private set; }

        public UserEntity()
        {
            Roles = new List<RoleEntity>();
        }

        public virtual void Validate()
        {
          ANewCastleValidationRunner
             .ValidateModel(this)              
             .AddCustomValidator(ValidateNonAdminUser)
             .AddCustomValidator(ValidateSomethingElse)
         }

        public static IEnumerable<ErrorInfo> ValidateNonAdminUser()
        {
            if (this.Username.ToLower().Equals("admin"))
                yield return new ErrorInfo("Username", "RuleNonAdmin");
        }
    }
}

I don't know to implement the ".AddCustomValidator(ValidateNonAdminUser)" part.

for reference this is the LocalizedCastleValidationRunner:

Code:
internal class LocalizedCastleValidationRunner
    {
        private static readonly CachedValidationRegistry registry = new CachedValidationRegistry();

        public static string LocalizedString(string key)
        {
            // allow for multiple parameters
            // syntax: parm1,parm2,parm3
            // will return string.format(parm1, string.format(parm2, parm3));
            var keys = key.Split(',');
            var res = new ResourceManager(typeof (SR)) {IgnoreCase = true};
            var message = string.Empty;
            try
            {
                for (var x = keys.Length - 1; x > -1; x--)
                {
                    var msg = res.GetString(keys[x].Trim(), Thread.CurrentThread.CurrentCulture);
                    if (message.Equals(string.Empty))
                    {
                        message += msg;
                    }
                    else
                        message = string.Format(msg, message);
                }
                return message;
            }
            catch
            {
                return key;
            }
        }

        public static IList<ErrorInfo> GetErrors(object instance)
        {            
            var result = new List<ErrorInfo>();
            var runner = new ValidatorRunner(registry);
            if (!runner.IsValid(instance))
            {
                var errorSummary = runner.GetErrorSummary(instance);
                result.AddRange(from prop in errorSummary.InvalidProperties
                                from err in errorSummary.GetErrorsForProperty(prop)
                                // err is in fact a key for our resource
                                select new ErrorInfo(prop, LocalizedString(err)));
            }
            return result;
        }

    }
}

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
or this would be even better:

Code:
...
        public virtual void Validate()
        {
            MyNewCastleValidator.Validate(this);            
        }

        public static ICustomValidator ValidateNonAdminUser()
        {
            // add custom businessrule here
        }

this would require that MyNewCastleValidator discovers all static methods that return a ICustomValidator and run them.

is this even possible?

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
you will get a better response in the castle forum.

it is possible to discover public static methods returning ICustomValidator using reflection. I have only used the castle validators for simple validation on my view models.

Jason Meckley
Programmer
Specialty Bakers, Inc.

faq855-7190
faq732-7259
 
it is possible to discover public static methods returning ICustomValidator using reflection

Busy on that, any pointers are welcome...

in fact I'm not doing validation on my viewmodels (as they are a collection of DTO's). I want validation built in on my domain models (entities) and because this is a multiculture project, I need to string resources.
I know that the latest castle build has multilang resources but I want to use my own resource files and own error messages. The reason I use castle is because it pluggable to xVal (client side validation with jquery). Are there better alternatives out there?

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
got it, lot happier now, but still pondering how to improve custom validation methods:

Code:
    public class UserEntity : EntityBase
    {
        [ValidateNonEmpty("RuleNotEmpty, Username")]
        public virtual string Username { get; set; }
        [ValidateNonEmpty]
        public virtual string Password { get; set; }
        [ValidateNonEmpty]
        public virtual string Fullname { get; set; }
        public virtual bool IsDeleted { get; set; }
        public virtual LanguageEntity Language { get; set; }
        public virtual IList<RoleEntity> Roles { get; private set; }

        public UserEntity()
        {
            Roles = new List<RoleEntity>();
        }

        public virtual void Validate()
        {
            LocalizedCastleValidationRunner.ValidateObject(this);
        }

        public static ErrorInfo ValidateNonAdminUser(UserEntity userEntity)
        {
            if (userEntity.Username.ToLower().Equals("admin"))
                return new ErrorInfo("Username", "RuleNonAdmin");
            return null;
        }
    }

my "new" validator:

Code:
internal class LocalizedCastleValidationRunner
    {
        private static readonly CachedValidationRegistry registry = new CachedValidationRegistry();

        public static string LocalizedString(string key)
        {
            // allow for multiple parameters
            // syntax: parm1,parm2,parm3
            // will return string.format(parm1, string.format(parm2, parm3));
            var keys = key.Split(',');
            var res = new ResourceManager(typeof(SR)) { IgnoreCase = true };
            var message = string.Empty;
            try
            {
                for (var x = keys.Length - 1; x > -1; x--)
                {
                    var msg = res.GetString(keys[x].Trim(), Thread.CurrentThread.CurrentCulture);
                    if (message.Equals(string.Empty))
                        message += msg;
                    else
                        message = string.Format(msg, message);
                }
                return message;
            }
            catch
            {
                return key;
            }
        }

        private static bool CheckMethod(MethodInfo method)
        {
            // our method must be static, public and has validate in it's name but is not named validate
            if (!method.IsPublic || !method.IsStatic || method.ToString().ToLower().Equals("validate"))
                return false;

            if (!method.ToString().ToLower().Contains("validate"))
                return false;
            return true;
        }

        private static IList<ErrorInfo> RunValidateMethods(object instance)
        {
            MethodInfo[] methods = instance.GetType().GetMethods();
            var errorInfoList = new List<ErrorInfo>();
            foreach (var m in methods)
            {
                if (CheckMethod(m))
                {
                    var userParameters = new object[1];
                    userParameters[0] = instance;
                    var errorInfo = (ErrorInfo)m.Invoke(instance, userParameters);
                    if (errorInfo != null)
                        errorInfoList.Add(errorInfo);
                }
            }
            return errorInfoList;
        }

        public static IList<ErrorInfo> GetErrors(object instance)
        {
            var result = new List<ErrorInfo>();
            var runner = new ValidatorRunner(registry);
            if (!runner.IsValid(instance))
            {
                var errorSummary = runner.GetErrorSummary(instance);
                result.AddRange(from prop in errorSummary.InvalidProperties
                                from err in errorSummary.GetErrorsForProperty(prop)
                                select new ErrorInfo(prop, err));
                result.AddRange(RunValidateMethods(instance));
            }
            return result;
        }

        public static void ValidateObject(object instance)
        {
            var errors = GetErrors(instance).ToList();            
            if (errors.Any())
                throw new RulesException(errors);
        }
    }

/Daddy

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top