我总是会在 BLL 上进行验证,因为它是您系统的核心。由于您的系统将通过可能最终超出您的控制范围或被具有不同需求的应用程序使用的服务公开,因此这是一种确保您的数据无论来自何处都有效的方法。
例如,想想这个例子:
MVC 应用 | 内部cmd工具| 第三方申请
服务层
业务层
您首先在核心业务和服务层之上创建一个 MVC 应用程序。然后有人认为创建一个可以在您的应用程序核心上执行某些操作的内部命令行工具将是一个好主意。如果您没有在业务层上进行验证,那么您将需要重复 MVC 应用程序所做的验证。您可以忍受这种情况,但如果您将服务暴露给第三方,您的服务层的消费者甚至可能无法控制。因此,最终完全信任您的数据的唯一方法是在持久化之前在业务层中进行验证。
此外,根据应用程序,在其他一些层上添加验证也很有用,例如 ASP MVC 应用程序上的控制器或客户端验证。这样操作会尽早失败,并尽快通知用户错误。
例如,在 MVC 应用程序中,简单的验证将在客户端使用 jquery 验证和 MVC 非侵入式验证进行,因此当发现错误时,它甚至不需要将数据发送回服务器并等待响应。您在控制器操作中还有另一个验证步骤,您的视图模型将被验证。如果在控制器上发现任何错误,它将被添加到 ModelState 中,并且用户通常会被重定向到显示错误并可以采取措施的屏幕。最后,您的应用程序核心将验证进入的数据,发现的任何错误都将发送回堆栈中。
正如您所说,您似乎会重复大量验证代码,但有一些方法可以最大限度地减少这种影响。当您使用 ASP MVC 时,一个示例可能是混合数据注释和您的验证库:
您可以在模型和业务对象上使用数据注释来进行最简单的验证,例如要求或正则表达式。您还可以开发自己的数据注释验证属性。
public class EmployeeModel
{
[Required]
public string Name {get; set;}
...
}
public class EmployeeEntity: BaseEntity
{
[Required]
public string Name {get; set;}
...
}
对于您的业务层,创建一个仅考虑数据注释属性的基本验证器。(类似于此处描述的方法:http:
//odetocode.com/blogs/scott/archive/2011/06/29/manual-validation-with-data-annotations.aspx)
public class BaseValidator<T> where T: BaseEntity
{
public virtual ValidationResult Validate(T entity)
{
... validate data annotations here ...
}
}
这将为您在客户端、控制器和业务层提供相同的基本规则集,主要与用户输入相关。
对于任何具有更复杂验证逻辑的实体,从仅考虑数据注释属性的验证器中派生出业务层上的特定验证器。为该实体类型添加特定且更复杂的验证逻辑。
public class EmployeeValidator: BaseValidator<EmployeeEntity>
{
public override ValidationResult Validate(EmployeeEntity entity)
{
base.Validate(entity);
... perform complex BLL calculations ...
}
}
最后,在控制器层中添加一些代码,将业务层引发的任何验证错误添加到 ModelState 中。例如,您可以在基本控制器类上添加这样的方法:
public void AddValidationsToModelState(ValidationResult validationResult)
{
foreach(var error in validationResult.Errors)
{
ModelState.AddModelError(error.property, error.message);
}
}
最后,您将获得一个通用的数据注释属性共享库和业务层的特定验证程序部分。希望能帮助到你!