Web 应用程序的表单验证 - 将域错误传播到客户端的设计?

Web application's form validation - design to propagate domain errors to client-side?

数据验证应发生在网络应用程序的以下位置:

我目前是 DDD 粉丝,所以我的应用程序中有 UI 和域层分离。

我也在尝试遵循规则,域模型永远不应包含无效数据。

那么,您如何在应用程序中设计验证机制,以便将域中发生的验证错误正确传播到客户端?例如,当领域模型抛出用户名重复的异常时,如何将该异常正确绑定到提交的表单?

一些启发了这个问题的文章可以在这里找到:http://verraes.net/2015/02/form-command-model-validation/

我在我所知道的网络框架中没有看到这样的机制。我首先想到的是让域模型在异常数据中包含导致异常的字段名称,然后在 UI 层中提供表单数据字段和模型数据字段之间的映射以正确显示用户上下文中的错误。这种方法有效吗?它看起来摇摇欲坠...有一些更好的设计示例吗?

虽然与, I think the 不完全相同的问题:

Encapsulate the validation logic into a reusable class. These classes are usually called specifications, validators or rules and are part of the domain.

现在您可以在模型层和服务层中使用这些规范。

如果您的 UI 使用与模型相同的技术,您也可以使用那里的规范(例如,当在服务器上使用 NodeJS 时,您可以在 JS 中编写规范,也可以在浏览器中使用它们)。

编辑 - 聊天后的附加信息

  • 创建细粒度的规范,以便您能够在规范失败时显示适当的错误消息。
  • 不要让业务规则或规范了解表单字段。
  • 只为业务规则创建规范,而不是为基本的输入验证任务(例如检查 null)创建规范。

我想分享我们在一个 DDD 项目中使用的方法。

  • 我们创建了一个 BaseClass 字段 ErrorId & 错误消息
  • 每个 DomainModel 都派生自这个 BaseClass,因此有两个额外的字段 ErrorId 和 ErrorMessage 可从 基类.

  • 每当发生异常时,我们都会处理异常(登录服务器,采取适当的步骤来补偿逻辑并从基于消息的客户端位置的本地化资源文件中获取用户友好消息)然后将数据传播为简单流而不引发或抛出异常。

  • 在客户端检查 ErrorMessage 是否不为空然后显示错误。

这是我们从项目开始就遵循的基本简单方法。

如果是新项目,这是最不复杂且最有效的方法,但如果您在大型旧项目中进行更改,这可能无济于事,因为更改很大。

要在每个字段级别进行验证,请使用 Enterprise Library 中的 Validation Application Block

它可以用作:

使用适当的属性修饰域模型属性,例如:

public class AttributeCustomer 
{
    [NotNullValidator(MessageTemplate = "Customer must have valid no")]
    [StringLengthValidator(5, RangeBoundaryType.Inclusive, 
        5, RangeBoundaryType.Inclusive, 
        MessageTemplate = "Customer no must have {3} characters.")]
    [RegexValidator("[A-Z]{2}[0-9]{3}", 
    MessageTemplate = "Customer no must be 2 capital letters and 3 numbers.")]
    public string CustomerNo { get; set; }
}

像这样创建验证器实例:

Validator<AttributeCustomer> cusValidator = 
            valFactory.CreateValidator<AttributeCustomer>();

使用对象并进行验证:

customer.CustomerNo = "AB123";
customer.FirstName = "Brown";
customer.LastName = "Green";
customer.BirthDate = "1980-01-01";
customer.CustomerType = "VIP";

ValidationResults valResults = cusValidator.Validate(customer);

检查验证结果为:

if (valResults.IsValid)
{
    MessageBox.Show("Customer information is valid");
}
else
{
    foreach (ValidationResult item in valResults)
    {
        // Put your validation detection logic
    }
}

代码示例取自Microsoft Enterprise Library 5.0 - Introduction to Validation Block 此链接将有助于理解验证应用程序块:

http://www.codeproject.com/Articles/256355/Microsoft-Enterprise-Library-Introduction-to-V

https://msdn.microsoft.com/en-in/library/ff650131.aspx

https://msdn.microsoft.com/library/cc467894.aspx