2012-01-04 59 views
2

我希望能够从我的服务类中执行验证。我有一个控制器的动作,看起来是这样的:将模型验证移动到服务类 - ASP.NET MVC

public ActionResult Edit(Post post) 
{ 
    if(!ModelState.IsValid) 
     return View(); 

    _postDataService.SavePost(post); 

    return View("Index"); 
} 

我不喜欢的事实,我_postDataService.SavePost()可以保存无效数据,我想在模型验证移动到我的_postDataService.SavePost( ) 方法。我的问题是什么是最优雅的方式来做到这一点?如果我将我的模型验证移动到我的Service方法,那么如何将模型错误返回给我的控制器?最后,模型验证会在哪里进行,如电子邮件地址的唯一性,因为它需要一些数据访问权限?在我看过的所有类似问题中,他们都没有提供直接的方法来做到这一点。

我也认为this解决方案,但这篇文章是旧的,我有一种感觉它不是最新的。

+0

是的,你提到的文章很旧,但其中提出的概念仍然存在 – 2012-01-04 11:31:59

回答

3

我假设你正在通过将属性放在Post模型/实体类中进行验证。如果是这样,你可以这样做在你的服务层验证:

var results = new List<ValidationResult>(); 
var isValid = Validator.TryValidateObject(post, 
    new ValidationContext(post, null, null), results, true); 

这主要是当它验证和配置的ModelState对象控制器/动作默认模型绑定器做什么。

这种方法的美妙之处在于,您不必从服务层返回验证错误。你只需要依靠默认的modelbinder自动完成上面的代码。如果有人试图在不检查ModelState.IsValid的情况下调用该操作,只需让您的服务方法抛出异常来提醒他们即可。

评论

是的,我的回答建议做两次确认后更新。

我感觉如何?我不介意。我们使用实体框架4.1与MVC,并且不使用MVC中的实体。相反,我们使用automapper来将实体DTO到单独的视图模型层中。我们的EF实体也用ValidationAttributes装饰,EF在任何DbContext.SaveChanges()操作期间自动评估。我们在viewmodel类的属性上应用了非常相似的验证属性。这可能看起来不干,并且确实存在重叠,但在某些情况下,UI侧的验证属性可能与域模型中的验证属性不同。

我们不在服务层进行验证。我们的服务层只是一个应用程序流程协调员,并且不负责任何业务规则。但是,验证在我们的应用程序中仍然发生两次首先,通过默认模型联编程序,针对视图模型验证规则。然后,如果交易使其成为EF,则对实体执行验证。所以我们实际上正在验证2个单独的图层。

如果你考虑一下,你真的在​​解决2个不同的问题。在UI中,您希望MVC向用户显示验证消息。 ModelState对此很好,因为它很好地与MVC验证(模型绑定/ jQuery /不显眼/客户端验证/等)挂钩。

相反,在域中,您正在保护您的数据完整性并执行业务规则。该域不关心向用户显示消息。众所周知,客户端可能是一台机器,WCF服务或其他东西。域的作用是防止事务发生,并且(在我们的情况下)抛出异常,而不是悄悄地试图与客户端“合作”。

+0

谢谢!我总是想知道模型粘结剂在做什么。所以你说保持if(!ModelState.IsValid)返回View();在我的操作控制器中,但通过在我的Service方法中再次调用验证逻辑来​​防止输入无效数据。您如何看待这样一个事实,即当没有验证错误时,验证会执行两次? – enamrik 2012-01-04 15:39:21

+0

嗨OliveHour,你的解决方案对于简单的验证很好,但可以说,对于上面的Post对象,我们必须验证Subject属性是唯一的;这将涉及到DB的旅程。我不认为这属于控制器,服务层或模型(即实现IValidatableObject),你认为如何? – 2012-01-22 03:49:42