在具有存储库,服务层和使用模型绑定器的ASP.Net MVC场景中应该进行验证?

hom*_*ata 5 validation asp.net-mvc

相关: 使用ASP.NET MVC实现字段验证的最佳方法是什么?

让我们假设一个具有以下项目的解决方案:

Foo; // the MVC web project
Foo.Models;
Foo.Repositories;
Foo.Services;
Run Code Online (Sandbox Code Playgroud)

Foo.Models是所有实体的应用程序域,无论使用EF,NH,POCO还是其他什么都无关紧要.这是一个例子:

public class User
{
    public string Username { get; set; }

    public string Email { get; set; }

    public string Password { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

Foo.Repositories那里有一个,UserRepository并且Foo.Services有一个UserService.

在Web应用程序中,让我们考虑如下的模型绑定器:

public class UserBinder : DefaultModelBinder
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

我在验证的位置上看到了三种不同的选项:

  • Foo.Models像下面这样:

    public class User
    {
        public string Username { get; set; }
    
        public string Email { get; set; }
    
        public string Password { get; set; }
    
        public ICollection<KeyValuePair<string, string>> ValidateErrors()
        {
            //Validate if Username, Email and Password has been passed
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • Foo.Services:像:

    public class UserService
    {
        public ICollection<KeyValuePair<string, string>> ValidateErrors()
        {
            //Validate if Username, Email and Password has been passed
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • Foo模型绑定器内部:

    public class UserBinder : DefaultModelBinder
    {
        protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var user = (User)bindingContext.Model;
    
            // validate everything here
    
            base.OnModelUpdated(controllerContext, bindingContext);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

另外需要注意的是,考虑前两个选项[模型和服务],还有另一个决定:ValidateErrors方法可以直接在控制器上或在Binder内部调用.

我对这个场景有2个问题:

  1. 验证应该是:

    • 在从控制器调用的模型中?
    • 在从粘合剂调用的模型中?
    • 在从控制器调用的服务中?
    • 在从绑定器调用服务?
    • 直接在宾德?
    • 还有其他想法吗?
  2. 以上所有场景都讨论了用户创建.但是用户登录呢?假设用户使用用户名和密码登录应用程序,因此不需要验证电子邮件.这个验证应该在哪里?

    • 在从控制器调用的模型中?
    • 在从控制器调用的服务中?
    • 还有其他想法吗?

hom*_*ata 0

经过大量研究后,我想我得到了问题的答案,所以我决定分享。

验证码应该在模型上。根据“瘦控制器,胖模型”的想法,并考虑到模型会知道它需要验证什么或不需要验证什么。

例如,假设我决定Foo.Models在其他解决方案中使用,但我决定不使用任何其他项目,并且验证在其他项目中进行。在这种情况下,我必须重新编码整个验证,这完全是浪费时间,对吗?

好的。验证代码必须在模型中,但是应该在哪里调用呢?

必须在将其保存到数据库或文件时调用此验证。正如在建议的场景中,我将存储库视为一个域,那么我们应该考虑在保存更改之前进行验证[在本示例中,我使用实体框架,但这不是必需的,只是为了显示]:


public class UserRepository : IRepository<User>
{
    public void Create(User user)
    {
        user.Validate();

        var db = dbFooEntities();

        db.AddToUsers(user);
        db.SaveChanges();
    }
}
Run Code Online (Sandbox Code Playgroud)

根据 MS 的建议,模型验证应该引发异常,并且控制器必须使用发现的错误填充 ModelState [一旦完成我的应用程序,我将尝试使用示例代码更新此答案]。

这样我们就有了问题#1 的答案。

关于登录验证的问题#2 怎么样?

由于登录不是持久保存数据的情况,因此验证应保留在服务上,因为在这种情况下登录是一项服务。

所以,问题的答案是:

  1. 在从存储库调用的模型中[由控制器调用]

  2. 在从控制器调用的服务中