【问题标题】:Validating Generic Property Validation Application Block验证通用属性验证应用程序块
【发布时间】:2011-12-28 00:06:49
【问题描述】:

我们有泛型属性

 public class BE
    {
        private List<Admin_Fee> _Admin_Fee = new List<Admin_Fee>();
        [StringLengthValidator(3,
        MessageTemplate = "Fund City Can't be more than 3 Chars")]  
        public MyProperty<string> FUND_CITY { get; set; }

        public MyProperty<int> SomeOtherProperty { get; set; }

        public List<MyPropertyBase> MyDataPoints { get; set; }

    }

我想将StingLengthValidator using VAB 放在通用属性上,并得到错误:

值不是预期类型

有人可以帮忙吗?

【问题讨论】:

    标签: .net validation generics enterprise-library


    【解决方案1】:

    您收到错误的原因非常简单:您尝试使用StringLengthValidator 来处理不是字符串的类型(实际上是MyProperty&lt;string&gt;)。

    问题是如何验证属性?这很棘手,因为该设计并不能很好地适应验证应用程序块设计。

    通常,您只需应用 ObjectValidator 来验证 MyProperty 类,但这并不适合这种情况,因为您似乎打算使用 MyProperty 来保存具有不同规则的各种值,因此您无法真正将验证器属性应用于MyProperty

    我认为您可以使用自定义验证器实现您想要的。我认为您可以将现有的验证器包装在您的自定义验证器中。

    这里我假设 MyProperty 看起来像:

    public class MyProperty<T>
    {
        public T Value { get; set; }
    }
    

    然后您可以创建自定义验证器 MyPropertyValidator:

    public class MyPropertyValidatorAttribute : ValidatorAttribute
    {
        Microsoft.Practices.EnterpriseLibrary.Validation.Validator validator;
    
        public MyPropertyValidatorAttribute(Type validator, params object[] validatorArgs)
        {
            this.validator = Activator.CreateInstance(validator, validatorArgs) 
                as Microsoft.Practices.EnterpriseLibrary.Validation.Validator;    
        }
    
        protected override Microsoft.Practices.EnterpriseLibrary.Validation.Validator DoCreateValidator(Type targetType)
        {
            return new MyPropertyValidator(validator);
        }
    }
    
    public class MyPropertyValidator : Microsoft.Practices.EnterpriseLibrary.Validation.Validator
    {
        Microsoft.Practices.EnterpriseLibrary.Validation.Validator validator;
    
        public MyPropertyValidator(Microsoft.Practices.EnterpriseLibrary.Validation.Validator validator)
            : this(validator.MessageTemplate, validator.Tag)
        {
            this.validator = validator;
        }
    
        public MyPropertyValidator(string message, string tag) : base(message, tag)
        {
        }
    
        protected override string DefaultMessageTemplate
        {
            get { return ""; }
        }
    
        public override void DoValidate(object objectToValidate, object currentTarget, string key, ValidationResults validationResults)
        {
            var val = objectToValidate;
    
            Type t = objectToValidate.GetType();
            var propInfo = t.GetProperty("Value");
    
            if (propInfo != null)
            {
                val = propInfo.GetValue(objectToValidate, null);
            }
    
            validator.DoValidate(val, currentTarget, key, validationResults);
        }
    }
    

    然后你可以像这样注释你的类:

    public class BE
    {
        [MyPropertyValidator( 
            typeof(StringLengthValidator), 
            0, RangeBoundaryType.Ignore,
            3, RangeBoundaryType.Inclusive,
            "Fund City Can't be more than 3 Chars",
            false)]
        public MyProperty<string> FUND_CITY { get; set; }
    
        [MyPropertyValidator(
            typeof(RangeValidator),
            0, RangeBoundaryType.Inclusive,
            10, RangeBoundaryType.Inclusive,
            "Must be between 0 and 10", 
            false)]
           public MyProperty<int> SomeOtherProperty { get; set; }
    }
    

    我没有对它进行广泛的测试,但它似乎有效。它确实有一些缺点:

    • 它不灵活。例如,它不支持复合验证器或其他更复杂的场景。您也许可以实现所有这些情况,但会变得一团糟。
    • 我的实现是使用反射,最好避免。
    • 值类型的潜在装箱

    【讨论】:

    • 感谢您的回复。当我实现此代码时,我收到错误“方法 'Level2.MyProperty`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].Value' not found。”在方法中:public override void DoValidate
    • @H.N.Mishra:由于您没有发布MyProperty 课程,我只是猜测示例中的内容。您需要将属性“值”更改为您需要在MyProperty 中验证的任何实际属性。
    • 不适用于集合属性:[MyPropertyValidator( typeof(ObjectCollectionValidator))] public List Admin_Fee { get{return _Admin_Fee; } set{} } 集合类型为:public class Admin_Fee {[MyPropertyValidator(typeof(StringLengthValidator), 0, RangeBoundaryType.Ignore, 1, RangeBoundaryType.Inclusive, "BP_Name Can't be more than 1 Chars", false)]public MyProperty BP_Name { 获取;放; } 公共 MyProperty BP { 获取;放; } 公共 MyProperty BP_Perc { 获取;放; } }
    • 是的,正如我所提到的,这是一种不灵活的方法,不能 100% 与 VAB 设计保持一致。 IE。 VAB 假设更多的是静态类型,其中验证器将放置在目标实体本身上,这是通常的应用程序设计。您将不得不做更多的工作来支持所有场景(即任意 T)。我已更新代码以仅在属性存在时才检索该属性……否则验证将直接委托给原始对象的 VAB。老实说,这种方法有点滑坡。
    【解决方案2】:

    我认为这里的问题是验证器是如何工作的。 StringLengthValidator 要求字符串在某些参数(最小和最大长度)内。但是,您放置此验证器的属性不是字符串,这是您的问题。您的类型是通用 T,如果您想使用验证属性对此属性进行某种排序字符串长度验证,则需要创建自定义验证器属性。

    MVC 示例(属性部分不需要 MVC)- http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx

    一般示例 - http://odetocode.com/Blogs/scott/archive/2011/02/21/custom-data-annotation-validator-part-i-server-code.aspx

    【讨论】:

      猜你喜欢
      • 2011-09-17
      • 2011-02-11
      • 1970-01-01
      • 2011-04-03
      • 1970-01-01
      • 1970-01-01
      • 2010-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多