4

根据我的经验,.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)还是我们需要使用规则引擎还是什么?你们在现实世界中是如何处理这种情况的?:-)

4

2 回答 2

6

我知道只有一个验证框架,那就是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 特有的,您选择的每个框架都会遇到相同的问题。我写过一篇文章描述了我们在这些情况下面临的复杂性(阅读和颤抖)。

第三个问题:你们在现实世界中是如何应对这种情况的?

我在生产代码中使用 VAB 进行这些类型的验证。它工作得很好,但是 VAB 不是很容易学习。尽管如此,我还是喜欢我们可以用 VAB 做的事情,而且只有在 v5.0 发布时它才会变得更好。如果您想学习它,请先阅读 ValidationHOL.pdf 文档,该文档可在动手实验室下载中找到。

我希望这有帮助。

于 2010-02-13T21:07:59.463 回答
0

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

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

下载中包含的代码应该作为一个易于遵循的示例来说明如何进行。这里的缺点是 ASP.Net 中包含的验证控件通常不能很好地与 asp.net-ajax 一起使用。

于 2010-02-13T18:13:51.337 回答