2012-03-13 130 views
4

让我先说这个问题,并说明使用实体框架不适合我们。企业中企业实体验证的首选方法

在我们的财务组织中,我们有跨越解决方案的业务实体。有些人拥有其他人不需要的界面。验证和业务规则必须包含在实体中。

我针对为我生成的DAL和DTO编写代码,这些DAL使用procs在数据库上运行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上苦心地复制了验证,因此我们获得了客户端和服务器端的验证。这里是同一属性的视图模型版本从上面:

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

这里的主要区别是,在实体验证加载错误插入的验证类的错误集合,可以在当时的实体进行查询去拯救自己。如果(!IsValid)则抛出一个包含错误数组的自定义异常。控制器通过它们循环并将它们添加到ModelState中。

我开始研究一些几乎有几百个字段的类。即使它们被面向对象分解,领域的数量仍然非常高。这些都是贷款认证等,对于单个记录有很多数据。必须写出对许多属性的验证使我想吐。我不能只编写一个实用程序来生成实体和验证,因为业务规则是驱动验证的原因,而不是数据库。这意味着一个字段在数据库中可以为空,但不允许根据业务规则保留为空值,或者该字段可以为空,但只有在单独的字段具有值时才是空的等。

所以,可以使用just View Model中的数据注释与实体的实现方式是否相同?我可以为非标准验证编写自定义验证器,然后为更复杂的内容编写业务规则。验证错误是否会从实体中获得更高的级别,以便UI可以像ModelState一样以友好的方式通知用户?其他人在这种情况下做什么?

+0

我有一个建议。在遇到无效输入或在通过业务规则引擎进行验证时规则未满足的任何情况下,只需冒泡该异常,以便可以在Controller中捕获该异常,然后将其添加到modelstate的错误集合中。例如:抛出一个自定义的异常,并且不要在规则引擎中捕获该异常,只需重新抛出,直到它到达控制器。然后使用Html.ValidationSummary()在UI中显示。 – Saravanan 2012-03-16 03:50:01

+0

这样做会奏效 - 但这个想法是为了避免评估集合中的属性或获取并提供更多的AoP设计模式。我已经在房产中找到了收集错误的策略。所有抛出异常都会提供一种不同的方式来向调用者显示错误。这只是交换不同代码的代码。我想消除属性中的代码。 – 2012-03-16 14:09:53

+0

内置的类型默认为必需,您不需要添加该属性。 – RickAndMSFT 2012-03-22 17:07:05

回答

3

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

至于建议的saravanan你可以使用异常通信在其它层UI层发现的验证错误(还可以配置WCF通信异常细节给客户端)

+0

这是一个有趣的策略。我将不得不更多地了解MetaDataTypes,看看它是否能够实现我期待的目标。不知道这是否会成为问题,但我的ViewModel通常是多个实体的子集,并且不映射1:1。假设我想要一个强化实体即使通过UI重新验证也是正确的。例如,如果用户界面受到影响并且ViewModel将实体设置为“活动”状态。企业中的业务规则和验证将评估和否定攻击。我需要看到一些很好的替代策略的具体例子。 – 2012-03-16 14:04:15

+0

“ViewModels通常是多个实体的子集并且不映射”。 您可以将Just 1 MetaDataType应用于每个对象,因此我建议这样做:不是将几个对象的属性混合到一个唯一的根类中,而是定义一个根ViewModel。这种根ViewModel的每个属性都包含一个子视图模型,其属性是JUST ONE BL对象属性的一个子集。这样每个ViewModel子可能具有的是不同的MetadataType。 属性是几个属性的组合(例如,价格总和直接放在根模型中或您想要的值) – 2012-03-16 14:42:05

+0

这样,每个子ViewModel都具有应用于其中的MetadataType中包含的属性的子集。 ...如果metadatatype无法在所应用的对象中找到ALL ITS PROPERTIES,则会出现一种设计错误,它会抛出一个异常(难以理解为什么?)。但是,我写了一个自定义的DataAnnotationsMetaDataprovider,它可以克服这个问题我把它放在我的开源项目“Mvc Controls Toolkit”中,但是如果你只需要DataAnnotationMetaDataProvider,我可以给你发一个独立的文件,你可以在你的项目中安装 – 2012-03-16 14:53:50