如何保持DRY与域对象和服务中的验证相对于UI层中的验证

问题描述

|| 我已经搜索了答案,甚至问了几个与此主题有关的问题,但还没有真正找到正确的答案。如何在POCO Domain对象和服务中向UI层公开验证方法?目前,我正在使用Web表单。 例如,我有以下域对象:
class Person
{
    public string Name { get; set; }
    public string Email { get; set; }

    public bool IsValidEmail(string email) {}
    public bool IsValidName(string name) {}

    public bool IsValidPerson()
    {
        if (IsValidEmail(Email) && IsValidName(Name)) { return true; }
        return false;
    }
}
和域服务:
class PersonService
{

    private Person person;
    private PersonRepository pRepo;

    public PersonService()
    {
        person = new Person();
        pRepo = new PersonRepository();
    }

    public AddPerson(Person p)
    {
        if (p.IsValidEmail(p.Email) && p.IsValidName(p.Name) && !DoesEmailExistInDatabase(p.Email))
        { pRepo.Save(p); }
        else
        { throw new ArgumentException(); }
    }

    public GetPersonByEmail(string email)
    {
        if (person.IsValidEmail(Email))
        { pRepo.GetByEmail(email)); }
        else
        { throw new ArgumentException(); }
    }

    public bool DoesEmailExistInDatabase(string email) { //code if exists.. }
}
和UI / Codebehind层: 通过电子邮件找人
string emailInput = EmailTextBox.Text;

PersonService pService = new PersonService();
Person p = new Person();

if(p.IsValidEmail(emailInput))
{
    Person myPerson = pService.GetPersonByEmail(emailInput);
}
else
{
    //give user error here...
}
为可能需要验证的域对象中的每个属性创建单独的验证方法是否正确? 域对象和服务中的那些方法是否应该是静态的,所以我不必仅仅为了进行验证而创建person的实例? 我是否应该在Service中公开来自Person域对象的验证,以便用户不需要知道从哪里查找(因为我将某些服务投入使用,而将一些POCO投入的原因实际上是实现问题)? 4.有更好的方法吗?     

解决方法

关于#1-是的(这是一种有效方法),前提是假定域对象最适合“知道”什么是正确的输入。 关于#2-是的。 关于#3-这样做没有什么害处,但是,如果您不信任类外部的某些事物能够/负责进行实际的验证,那么为什么您会信任它调用验证呢? 设置值后,我将强制执行验证,一旦您在对象中具有“好数据”,以后就无需验证它了。这导致第4点... 关于#4-以某种方式提供/公开验证的好处是系统的其他部分可以使用它;经典示例在用户界面上,您可以通过验证输入或提交的输入来提供更好的用户体验。 验证的另一种方法是确定(从总体角度看)什么样的好数据-并为(独立的)公共域级别“服务”定义一堆规则。验证每个域对象内的输入是不错的选择,因为随着各个域对象随着时间的推移逐渐成熟(可以限制孤立更改的影响),您可以更改特定的规则-缺点是您将重复很多规则。 普通服务可以解决此问题,服务会说“这是有效的电子邮件地址的样子”,您所有的域对象都将服从该服务以告诉他们什么是好的电子邮件地址。 使用这种方法的“技巧”是要小心命名验证方法的方式-不要太含糊或模棱两可。例如,您可能会发现大多数具有电子邮件属性的域对象都使用一种\“ main \”电子邮件验证方法
ValidateGenericEmail()
,但是您经常会遇到其他对象是具有特殊规则
ValidateCorporateEmail()
的特殊情况。可以,将它们添加到验证服务中,因为这是域层中用于管理这些规则的中心位置。 然后,您的域对象仍然可以执行您需要他们做的所有事情-除了将规则拉到单独的公共位置。     ,我只会在表示层上进行验证,并从中清除域模型。因此,域模型假设数据已经过验证(是经过验证的,不是吗?)。还是您有其他数据来源?  这将使您的域模型更加纯净,您将看到其核心。但是在对象的创建时通过使用保护子句检查构造函数参数来强制执行一些约束是很不错的。