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

时间:2012-03-13 20:00:45

标签: asp.net-mvc-3 validation design-patterns c#-4.0

让我先说明这个问题并说明使用实体框架不是我们的选择。

在我们的金融机构中,我们拥有将在整个解决方案中使用的业务实体。有些人拥有其他人没有的UI。验证和业务规则必须包含在实体中。

我针对为我生成的DAL和DTO进行编码,这些DAL使用procs在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类的错误集合中,可以在实体保存自身时查询。如果(!IsValid)则抛出包含错误数组的自定义异常。控制器通过它们循环并将它们添加到ModelState。

我开始研究一些几乎有几百个字段的类。即使他们被OO分解,领域的数量仍然很高。这些是贷款证明等,其中包含大量单个记录的数据。必须写出许多属性的验证让我想要呕吐。我不能只编写一个实用程序来生成实体和验证,因为业务规则是驱动验证的因素,而不是数据库。意味着字段可以在db中为空,但不允许根据业务规则保持为null,或者该字段可以为null,但仅当单独的字段具有值等时才会这样。

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

1 个答案:

答案 0 :(得分:3)

通常,属性上的验证属性可以获得不同的验证结果(验证是否通过),具体取决于它是在UI层,BUsiness Layer还是DAL中进行评估。例如,考虑一个必需属性,如果在ViewModel上应用它可能会失败,但是在业务层中它可以简单地传递,因为用户未提供的值是从其他来源提供的。 但是,验证规则(如电子邮件的格式)始终会得到相同的结果。但是,存在可能需要在业务层中重复验证的精简问题......仅仅因为Web服务器更容易受到攻击并且更容易受到攻击。但是,重复两次相同的验证并不意味着编写两次代码。您可以在公共dll中收集要应用于多个图层的所有属性,您可以在其中定义应用于同一概念实体的各种版本(ViewModel,BL,DAL)的MetaDataType。这样,您就可以在不重复代码的情况下满足安全要求。

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