c# - 如何通过域对象和服务中的验证与 UI 层中的验证保持 DRY

标签 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/代码隐藏层:

通过电子邮件找人

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. 域对象和服务中的那些方法是否应该是静态的,这样我就不必创建 person 的实例来进行验证?

  3. 我是否应该在服务中公开来自 Person 域对象的验证,以便用户不需要知道在哪里寻找它们(因为我将一些放在服务中,将一些放在 POCO 中确实是实现问题)?

4.有没有更好的办法?

最佳答案

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

回复 #2 - 是的。

关于 #3 - 这样做没有坏处,但是,如果您不相信类外部的某些东西能够/负责实际验证,那么为什么您会相信它会调用验证?

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

Re #4 - 以某种方式提供/公开验证的好处是系统的其他部分可以使用它;典型示例是在 UI 中,您可以在其中通过在输入或提交时验证输入来提供更好的用户体验。

另一种验证方法是确定好的数据(在整体 View 中)是什么样的 - 并为那些作为(单独的)公共(public)域级别“服务”存在的规则定义一堆规则。验证每个域对象内的输入是好的,因为随着各个域对象的成熟,您可以更改特定规则(您限制了孤立更改的影响)——缺点是您将重复很多规则。

一个公共(public)服务会解决这个问题,一个服务会说“这就是一个有效的电子邮件地址的样子”,你所有的域对象都会听从这个服务来告诉他们什么是好的电子邮件地址。

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

您的域对象仍然可以执行您之前需要它们执行的所有操作 - 除了您已将规则提取到一个单独的公共(public)位置。

关于c# - 如何通过域对象和服务中的验证与 UI 层中的验证保持 DRY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6144789/

相关文章:

c# - 使用 Zxing 库、Xamarin.android 应用程序扫描时,将屏幕方向锁定为纵向。

c# - C# switch出现异常后如何继续

c# - Protobuf-net序列化/反序列化

asp.net - 未提供的参数化查询

c# - 从对象中读取验证属性

c# - 比较请求中的属性是否具有相等的值 C#

asp.net - App_Data 文件夹中的数据库 -> 无法打开物理文件 "xyz.mdf"

javascript - 防止在 ASP.NET 中选择默认值时发生下拉菜单的 Selected Index Changed 事件

validation - 我们可以在触发 JSF 验证器之前执行方法吗?

asp.net mvc 重定向到操作而不触发当前 View 中的验证?