在中间层验证

时间:2008-10-30 18:17:32

标签: c# validation middle-tier

我想对我的业务代码进行验证。我正在考虑两种方法来做到这一点。

一,以下列方式对我的类属性设置器进行验证

class Student{
    public string Name{
        get { return _name; }
        set {
            if (value.IsNullOrEmpty) throw exception ...
        }
    } 
} 

现在,这种方法的问题在于,每次分配名称时都会运行验证代码,这可能是我们可能不需要的,就像填入数据库中的数据一样。

我更喜欢两个,将静态方法放在这些实体类上,比如

class Student {
    public **static** void ValidateName(**string name**) {
        if (string.IsNullorEmpty(name)) 
        {
            throw ...
        }
        ...
    } 

注意我使用静态方法而不是实例方法,比如

class Student{
    public void Validate() {
        // validation logic on instance properties
        if (string.IsNullorEmpty(Name)) 
        {
            throw ...
        }

        ...
    } 

是因为我并不总是得到一个学生obj传入,我确实得到像字符串名称这样的原始类型经常传递给一个方法,比如

public static FindStudentByName(string name)
{
   // here I want to first do validation
   Student.ValidateName(name);

   // query DB
   ...
}

如果我确实通过了学生obj,那么我当然可以

public static AddStudent(Student s)
{
    // call the instance method
    s.Validate();
}

现在,我想让事情变得非常简单,所以我不希望采取以下任何一种方法

  1. 在属性上使用属性,例如[StringLength(25)]。

    其中一个,因为这需要反思并影响性能,有一些技巧可以降低性能,但我想再次保持它更简单。

    二,我希望我的网站能够在Medium Trust中运行。正如我所理解的那样,它需要完全信任。

  2. 使用任何验证块,例如MS。在CodePlex上找到企业库等。

  3. 现在,我希望对此有所了解,

    我采用的方法有哪些潜在的问题?
    这种方法比其他方法更好,更易读,更易于维护吗?

    您如何在中间层进行验证?

    感谢一帮!

    雷。

3 个答案:

答案 0 :(得分:4)

我使用规则引擎在中间层执行域验证,非常类似于written about here。朋友的项目使用的方法类似于您在后一个示例中提出的方法,最终结果是不可维护的(脆弱,难以实现通用验证UI)。规则引擎方法是可维护的,因为它将所有验证和持久性规则本地化在一个组织良好的位置,并将每个规则作为完全成熟的类 - 但是在域类上公开类似于您提议的验证。有些人喜欢动态编译,因此他们将它们存储在数据库中,以实现高水平的部署后配置;在我的情况下,我喜欢它们编译时检查,因此有一些规则定义,在静态类上暴露了lambdas。

我知道这与你想做的事情不一致,但是问我怎么做,并说其他方法不够简单,就像说“你怎么写可靠的代码,我想保持这很简单,所以单元测试是不可能的。“对我来说,将每个规则视为自己的类很好,因为它更容易维护和记录,但实现起来更复杂。

答案 1 :(得分:1)

选项二实际上并不强制执行验证,至少在没有手动调用验证的情况下。因此,对象的使用者可能违反规则。

我个人会使用类似于您的第一个示例,因为它确保所有数据都有效。这是对数据库方面的额外检查,但从我注意到的情况来看,这通常不是什么大问题。

答案 2 :(得分:1)

您建议的方法似乎表明不应始终应用验证集。哪个好。我已经看到了大多数时间我们想要的大量规则和验证,但并非总是如此。因此,问题变成“您希望何时应用这些验证”?

比方说,例如,你有一些验证,你总是想要申请,有些你只想验证......我不知道..你要保存到存储(数据库)。 在这种情况下,应用的检查始终应该在属性中(请参阅下面的详细信息),并且仅在您要保存到存储时应用的检查应该在方法中(可能以'在适当时调用的VerifyRulesForStorage')(例如,在'Sa​​veToStorage'方法的中间)。

我认为值得考虑的一件事是,当您在多个实体中进行相同的验证时,可能会产生重复。无论是在属性中,还是在“VerifyRulesForStorage”方法中,您可能会在许多类中的许多地方进行相同的检查(例如:String.IsNullOrEmpty,或CheckItsANumber,或CheckItsOneOfTheAcceptedValues等等)。 当然,您可以通过继承来解决这个问题(例如,您的所有实体都从具有实现每种类型检查的方法的基本实体类继承)或组合(可能是更好的方法,以便您的实体的类树由其他人驱动,更合适的考虑因素,例如:所有实体都有一个实现所有这些检查的Validator对象。 无论哪种方式,您可能希望远离静态方法,如果您是测试驱动的话,它们往往会产生有问题的情况(有需要的方法)。

在我们的系统中,我们实际上有描述验证规则的元数据。类的属性名称用于检索正确的元数据,然后告诉系统应用哪些规则。然后我们有一个验证器对象,它通过工厂实例化实际执行验证的正确类型的对象(例如,我们有一个实现IsRequiredString规则的类,一个实现IsNumber规则的类等等)。听起来很复杂,但是,像我们这样的lrge系统,它绝对值得。

最后,那些现成的图书馆可能是一个不错的选择。在我们的例子中,他们并不是因为我们有特殊的要求 - 但总的来说......使用其他人开发(并且会支持)的轮子比建立自己的轮子有好处(相信我,我喜欢重建车轮,当我可以..我只是说有些情况下每种方法都比另一种更好。)