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

时间:2011-05-26 20:41:30

标签: c# asp.net validation architecture domain-driven-design

我已经搜索了答案,甚至就这个问题提出了几个问题,但还没找到正确的答案。如何将POCO域对象和服务中的验证方法公开给UI层?目前我正在使用网络表单。

例如,我有以下域对象:

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...
}
  1. 为域对象中可能需要验证的每个属性创建单独的验证方法是否正确?

  2. 域对象和服务中的那些方法是否应该是静态的,所以我不必创建人员实例来进行验证?

  3. 我是否应该公开服务中Person域对象的验证,这样用户就不需要知道在哪里查找它们了(因为我把一些服务器放在了POCO中的原因是真的一个实施问题)?

  4. 4.有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

Re#1 - 是(这是一种有效的方法),假设域对象最适合“知道”正确的输入是什么。

Re#2 - 是的。

Re#3 - 这样做没有坏处,但是,如果你不相信课外的东西能够/负责实际的验证,你为什么会相信它来调用验证呢?

我会在设置值时强制执行验证,一旦在对象中有“好数据”,就不需要稍后验证它。这导致了第4点......

Re#4 - 以某种方式提供/暴露验证的奖励是系统的其他部分可以使用它;经典的例子是在UI中,您可以通过验证输入或提交的输入来提供更好的用户体验。

另一种验证方法是确定哪些好的数据(在整体视图中) - 并为那些作为(单独的)公共域级“服务”存在的规则定义一堆规则。验证每个域对象内部的输入是好的,因为随着时间的推移,您可以更改特定规则,因为单个域对象会随着时间的推移而成熟(您可以限制隔离更改的影响) - 缺点是您将重复许多规则。

一个常见的服务可以解决这个问题,一个服务会说“这就是一个有效的电子邮件地址”,你的所有域对象都会推迟服务,告诉他们一个好的电子邮件地址是什么。

这种方法的“技巧”是要小心你如何命名验证方法 - 不要太模糊或含糊不清。例如,您可能会发现大多数具有电子邮件属性的域对象使用一种“主”电子邮件验证方法ValidateGenericEmail()的情况,但您经常会遇到其他对象是具有特殊规则的特殊情况的情况{{ 1}}。没关系,将它们添加到验证服务中,因为这是域层中用于管理这些规则的中心位置。

您的域对象仍然可以执行之前需要他们执行的所有操作 - 除非您已将规则撤回到单独的公共位置。

答案 1 :(得分:0)

我只在表示层和清理域模型上保持验证。因此,域模型假定数据已经过验证(并且已经过验证,不是吗?)。或者你有另一个数据源可以来自哪里?  这将使您的域模型更加纯粹,您将看到它的核心。但是通过使用guard子句检查构造函数参数,在对象的创建时强制执行一些约束是不错的。