推荐在哪个位置执行验证:ViewModel、Model还是Controller?

3
我有一个注册页面,希望能对重复的用户名和电子邮件地址进行一些验证(除了ViewModel上的StringLength和Required注释之外)。目前我在控制器中执行此验证,当注册表单被提交时。但我不确定这是否是正确的地方。
我无法想象ViewModel是正确的位置,因为它需要ViewModel引用我的UserRepository。将这种验证放在模型类中是否有意义?
如果有的话,我该如何在模型上实现它,以便在将其发送到我的存储库之前检查信息是否有效?
更新:
我的控制器操作代码:
if (ModelState.IsValid)
        {
            if (!_userRepository.Exists(registerViewModel.Username))
            {
                if (!_userRepository.EmailExists(registerViewModel.Email))
                {
                    _userRepository.Add(
                        new User
                            {
                                Created = DateTime.Now, 
                                Email = registerViewModel.Email, 
                                Password = registerViewModel.Password, 
                                Username = registerViewModel.Username
                            });

                    _userRepository.SaveChanges();
                    TempData["registrationDetails"] = registerViewModel;

                    return RedirectToAction("Confirm");
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "This email address is already in use.");
                }
            }
            else
            {
                ModelState.AddModelError(string.Empty, "This username is already taken.");
            }
        }

        return View(registerViewModel);
    }

更新2

领域模型是否应该关心重复的用户名或电子邮件地址等约束条件,还是这是控制器层应该担心的事情?

更新3

将验证逻辑放在控制器中似乎是最有意义的,因为它可以在远程验证和提交时的模型验证中重复使用。检查重复项之类的操作通常应该在控制器中完成,还是在领域模型中进行这些检查有意义呢?

谢谢。


这可能更多地取决于您的应用程序——我的应用程序的90% ViewModel 是我的数据层模型,那是我定义验证规则的地方,以便我可以重复使用它们——如果在控制器中完成,您必须每次重新使用模型/ViewModel时都要重新编写验证代码。 - Rob
这是我目前在使用ViewModels时遇到的问题之一。我在其中进行了验证,但我的模型类中也有验证。这感觉有点重复了。 - b3n
5个回答

1

我会在前端(可能是ajax)和后端都执行它 - 这取决于您的解决方案架构。

我喜欢让用户立即知道是否会出现注册问题。在我的典型数据层/业务层和表示层设置中,我会在业务逻辑中执行重复检查,并让控制器调用该代码片段(除了前端用户的ajax查找)。

顺便说一下:我通常更喜欢在Windows应用程序中仅使用MVVM(带有视图模型)。将MVC与MVVM结合使用可能会使事情变得不必要地复杂。


我在我的ViewModel上执行此操作。但是ViewModel仅包含用户名、电子邮件和密码。因此,我只能检查是否输入了任何内容以及电子邮件地址是否有效。使用IsValid方法,我无法检查重复的电子邮件地址或用户。 - b3n
@b3n - 你需要在业务逻辑中创建函数来进行重复检查,并在IsValid检查通过后调用它。如果重复检查失败,则只需将相同的视图传回并显示适当的错误消息给用户即可。- 编辑 - 我从上面的代码示例中看到这就是你正在做的。 - Chris Klepeis
这基本上就是我现在正在做的事情。不过,将这些方法移动到我的模型类中,然后例如在我的模型类上实现IValidatableObject,这样做是否有意义呢?然后我可以创建一个User对象,在将其传递到存储库之前调用Validate方法。然后验证逻辑将驻留在我的模型类中,而不再是控制器中。 - b3n
我真的不同意这里的观点。例如knockoutjs/backbone这样的库允许使用MVVM创建非常易用的网站,在今天的时代中,我认为你不能满足于任何更少的东西。在我看来,MVVM是未来的方向(即使它需要稍微多一些工作),出于同样的原因,我不同意将模型层用作视图模型。 - neebz
@nEEbz - 感谢您的反馈。就像任何事情一样,这是一个不断学习的过程。我会查看您提到的那些库。 - Chris Klepeis

0
正如Rob在评论中所说,这取决于您的应用程序结构。我倾向于进行双重验证(对我的ViewModels进行验证以及对我的服务层进行验证),以确保击中服务的数据是有效的。这有助于因为我的服务被多个客户端使用,但视图和ViewModels是特定于客户端的。前端验证具有即时反馈的优点,后端验证有助于保持数据的清洁。

0

我的建议是 - 对于验证,如重复的电子邮件地址和用户名 - 保持您的验证方法在控制器中。

或者在您的验证层 - 它将用于视图模型和数据层之间

对于MVC3,您将能够通过Remote属性将方法添加到控制器作为操作,以获得即时结果


0

我建议你在控制器中完成这个任务。

主要原因是无论应用程序的结构如何,你都需要使用Ajax来通知用户用户名是否已被占用。否则,这只会导致糟糕的可用性,这并不能证明你的代码结构合理。

为此,你需要一个操作方法,可以通过Ajax方式查看用户名是否存在。

总的来说,这意味着你可能会得到两组验证方法(UI和模型),但这都是为了更好的效果。

另外,为了使网站更易用,你肯定会使用像knockoutjs或backbone这样的JavaScript框架。这是真正的MVVM,在这种情况下,将ViewModels作为Model层类(如Chris所提到的)并不是一个好主意。因此,你最终仍然会得到两组验证。


我计划在将来的阶段在我的页面上使用RemoteValidation。现在,我只是试图理解我应该在哪里放置重复名称/电子邮件验证。我也认为视图模型比使用域模型类更清晰,因为它们包含了视图所需的更多信息。 - b3n
这不仅仅是关于更干净的代码。有时你需要在客户端使用一些视图模型数据。将模型类转换为Json格式是绝对不可取的。无论如何,为了获得更好的可用性网站和可管理的客户端代码,你需要拥有单独的视图模型。干杯! - neebz

0

你应该在视图(客户端)和控制器(服务器端)中进行验证。如果你使用的是MVC 3,你可以使用新的RemoteAttribute。它使用jQuery来进行服务器端调用,在其中你可以检查用户或电子邮件地址的存在。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接