代码之家  ›  专栏  ›  技术社区  ›  Jeffrey Cameron

.NET中可以在字段之间进行编辑的验证框架

  •  4
  • Jeffrey Cameron  · 技术社区  · 14 年前

    根据我的经验,.NET中的许多验证框架允许您一次验证一个字段,例如确保字段是邮政编码或电子邮件地址。我通常称之为字段编辑。

    在我的项目中,我们经常不得不在字段编辑之间进行。例如,如果您有这样的类:

    public class Range
    {
        public int Min { get; set; }
        public int Max { get; set; }
    }
    

    您可能希望确保max大于min。也可能希望对外部对象进行一些验证。例如,如果您有这样的类:

    public class Person
    {
        public string PostalCode { get; set; }
    }
    

    无论出于什么原因,您希望确保邮政编码存在于提供给您的数据库或文件中。我有一些更复杂的例子,比如用户提供了一个数据字典,而您希望根据该数据字典验证您的对象。

    我的问题是:我们是否可以为.NET使用任何现有的验证框架(tnvalidate、nhibernate validator),或者我们是否需要使用规则引擎或什么?你在现实世界中是如何处理这种情况的?-)

    2 回复  |  直到 10 年前
        1
  •  6
  •   Steven    10 年前

    我知道只有一个验证框架,那就是 Enterprise Library Validation Application Block 或者简称为vab。我将从VAB的背景回答您的问题。

    第一个问题:您能在VAB中进行状态(字段间)验证吗?

    是的,你可以。有多种方法可以做到这一点。您可以选择自验证机制,如下所示:

    [HasSelfValidation]
    public class Range
    {
        public int Min { get; set; }
        public int Max { get; set; }
    
        [SelfValidation]
        public void ValidateRange(ValidationResults results)
        {
            if (this.Max < this.Min)
            {
                results.AddResult(
                    new ValidationResult("Max less than min", this, "", "", null));
            }
        }
    }
    

    我必须说,我个人不喜欢这种类型的验证,尤其是在验证我的域实体时,因为我喜欢将验证与验证逻辑分开(并且保持我的域逻辑不受任何验证框架的引用)。但是,与编写自定义验证器类的替代方法相比,它们需要的代码要少得多。下面是一个例子:

    [ConfigurationElementType(typeof(CustomValidatorData))]
    public sealed class RangeValidator : Validator
    {
        public RangeValidator(NameValueCollection attributes)
            : base(string.Empty, string.Empty) { }
    
        protected override string DefaultMessageTemplate
        {
            get { throw new NotImplementedException(); }
        }
    
        protected override void DoValidate(object objectToValidate,
            object currentTarget, string key, ValidationResults results)
        {
            Range range = (Range)currentTarget;
    
            if (range.Max < range.Min)
            {
                this.LogValidationResult(results,
                    "Max less than min", currentTarget, key);
            }
        }
    }
    

    编写完这个类之后,您可以将这个类挂接到验证配置文件中,如下所示:

    <validation>
      <type name="Range" defaultRuleset="Default" assemblyName="[Range Assembly]">
        <ruleset name="Default">
          <validator type="[Namespace].RangeValidator, [Validator Assembly]"
            name="Range Validator" />
        </ruleset>
      </type>
    </validation> 
    

    第二个问题:如何通过可能的交互来进行复杂的验证(使用VAB)。

    我为第一个问题给出的示例也适用于此。您可以使用相同的技术:自我验证和自定义验证。您希望检查数据库中的值的场景实际上是一个简单的场景,因为对象的有效性并不基于其上下文。您可以根据数据库简单地检查对象的状态。当一个对象所处的环境变得重要时,它会变得更加复杂(但使用VAB是可能的)。例如,假设您希望编写一个验证,以确保每个客户在给定的时间段内拥有不超过两个未发货订单。这不仅意味着您必须检查数据库,而且可能需要在同一上下文中添加新订单或删除订单。这个问题不是特定于VAB的,对于您选择的每个框架,您都会遇到相同的问题。我已经写了 an article 这描述了我们在这些情况下面临的复杂性(阅读和颤抖)。

    第三个问题:现实世界中的人们如何处理这种情况?

    我使用生产代码中的VAB进行这些类型的验证。它工作得很好,但是vab不是很容易学的。不过,我喜欢我们可以用VAB做什么,只有当v5.0出现时,它才会变得更好。当你想学习它时,从阅读validationhol.pdf文档开始,你可以在 Hands-On Labs 下载。

    我希望这有帮助。

        2
  •  0
  •   Joel Coehoorn    14 年前

    当我需要任何开箱即用的东西时,我会构建自定义验证控件。这里的好处是这些自定义验证器是可重用的,它们可以作用于多个字段。下面是我发布到代码项目的一个示例,它是一个at least one of验证器,它允许您要求一个组中至少有一个字段具有值:

    http://www.codeproject.com/KB/validation/AtLeastOneOfValidator.aspx

    下载中包含的代码应该是一个简单易懂的示例,说明如何进行下载。这里的缺点是ASP.NET中包含的验证控件在ASP.NET-AJAX中通常不能很好地工作。