企业中业务实体验证的首选方法



让我在这个问题的前面陈述一下,使用实体框架不是我们的选择。

在我们的金融组织中,我们有将在解决方案中使用的业务实体。有些有用户界面,有些没有。验证和业务规则必须包含在实体中。

我根据DAL和为我生成的DTO进行编码,这些DAL使用proc在DB上操作CRUD(可以是SQL,也可以是Oracle)。

因此,当我创建MVC、WCF、控制台应用程序等时,问题一直困扰着是否可以实现更好的验证方法。

以下是实体对象中的几个典型属性:

[DefaultValue("")]
public string Branch {
    get { return _branch; }
    set {
        if (value != null && value == _branch) return;
        const string propertyName = "Branch";
        ValidationInstance.Clear(propertyName);
        ValidationInstance.ValidateRequired(propertyName, value);
        ValidationInstance.ValidateNumeric(propertyName, value);
        ValidationInstance.ValidateLength(propertyName, value, 2);
        _branch = value;
        if (EntityState != EntityStateType.New)
            EntityState = EntityStateType.Changed;
    }
}
    [DefaultValue(0)]
public decimal HighDefermentMargin {
    get { return _highDefermentMargin; }
    set {
        if (value == _highDefermentMargin) return;
        const string propertyName = "HighDefermentMargin";
        ValidationInstance.Clear(propertyName);
        ValidationInstance.ValidateRange(propertyName, value);
        _highDefermentMargin = value;
        if (EntityState != EntityStateType.New)
            EntityState = EntityStateType.Changed;
    }
}

正如您所看到的,数据注释和对验证类的显式调用相结合,可以执行越来越详细的验证。

在MVC应用程序中,我们煞费苦心地在ViewModel上重复验证,以便获得客户端和服务器端的验证。以下是上面相同属性的ViewModel版本:

[Required]
[Range(0.0, 99.99)]
[Display(Name = "High Deferment Margin")]
public decimal HighDefermentMargin { get; set; }

这里的主要区别在于,实体中的验证将错误加载到validation类上的错误集合中,该集合可以在实体保存自身时进行查询。If(!IsValid)然后抛出一个包含错误数组的自定义异常。控制器循环通过它们并将它们添加到ModelState。

我开始研究一些有几百个字段的类。即使它们被OO分解,字段的数量仍然很高。这些是贷款证明等,有大量的数据为一个单一的记录。不得不写下对这么多属性的验证,这让我想吐。我不能只编写一个实用程序来生成实体和验证,因为驱动验证的是业务规则,而不是数据库。这意味着一个字段在数据库中可以为null,但根据业务规则不允许保留为null,或者该字段可以为null但仅当一个单独的字段有值时,等等

那么,仅使用视图模型中的数据注释和实体是否可以以相同的方式获得相同的结果?我可以为非标准验证编写自定义验证器,然后为更复杂的东西编写业务规则。验证错误是否会从实体上升到更高的级别,以便UI可以以与ModelState相同的友好方式通知用户?在同样的情况下,其他人在做什么?

通常,属性上的验证属性可以获得不同的验证结果(验证是否通过),这取决于它是在UI层、业务层还是DAL中进行评估。例如,考虑一个Required属性,如果应用于ViewModel,它可能会失败,但在业务层中,它可以通过,因为用户没有提供的值是从其他来源提供的。但是,像电子邮件格式这样的验证规则。。。总是得到相同的结果。然而,也存在一些问题,可能需要在业务层中重复验证。。。这仅仅是因为web服务器更容易受到攻击,更易受到攻击。然而,重复两次相同的验证并不意味着编写两次代码。您可以在一个通用dll中收集要在多个层中应用的所有属性,在该dll中定义应用于同一概念实体的各种版本(ViewModel、BL、DAL)的元数据类型。通过这种方式,您可以在不复制代码的情况下满足安全性要求。

根据saravanan的建议,您可以使用异常将在其他层中发现的验证错误传达给UI层(您也可以配置WCF将异常详细信息传达给客户端)

最新更新