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

时间:2015-11-11 12:04:23

标签: validation architecture domain-driven-design

数据验证应在Web应用程序的以下位置进行:

  • 客户端:浏览器。加速用户错误报告
  • 服务器端:控制器。检查用户输入是否在语法上有效(没有sql注入,例如,所有传入字段的有效格式,所有必填字段都填写等)。
  • 服务器端:模型(域层)。检查用户输入是否在域中有效(没有重复的用户名,帐户余额不是负数等)。

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

我也试图遵循这个规则,域模型永远不应该包含无效数据。

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

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

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

2 个答案:

答案 0 :(得分:5)

虽然与this one不完全相同,但我认为answer is the same

  

将验证逻辑封装到可重用的类中。这些类通常称为规范,验证器或规则,并且是域的一部分。

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

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

编辑 - 聊天后的其他信息

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

答案 1 :(得分:2)

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

  • 我们创建了一个 BaseClass ,其字段为 ErrorId & 的的ErrorMessage 即可。
  • 每个DomainModel派生自此BaseClass&因此有两个额外的字段ErrorId& ErrorMessage可从 的BaseClass。

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

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

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

如果这是新项目,这是最不复杂的&有效的方法,但如果你在大型旧项目中进行更改,这可能会有所帮助,因为变化很大。

要在每个字段级别进行验证,请使用企业库中的验证应用程序阻止

可以用作:

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

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>();

使用对象&amp;做验证为:

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