【问题标题】:How is service validation communicated back to the controller?服务验证如何传回控制器?
【发布时间】:2011-02-27 06:08:08
【问题描述】:

我想我在这里遗漏了一些基本的东西,但我已经挖掘了两个多小时,而且肯定只是忽略了显而易见的东西。如果是这样,我很抱歉。

我有一个 MVC 3 站点,我有一个与我的控制器通信的服务层,以及一个与我的服务层通信的存储库(所有这些都使用 IoC 容器解耦,但这在这里无关紧要)。我的域模型是 EF4 实体,在控制器、服务和存储库之间共享。

我有一个看起来像这样的注册视图模型:

public class SignupViewModel
{
    [DisplayName("Email")]
    [Required, RegularExpression(@"^.+@.+\..+$")]
    public string Email { get; set; }

    [DisplayName("Password")]
    [Required]
    public string Password { get; set; }

    [DisplayName("Confirm password")]
    [Required, Compare("Password")]
    public string PasswordConfirmation { get; set; }
}

我的用户域模型如下所示:

public class User
{
    public int Id { get; set; }
    public string Email { get; set; }
    public string PasswordHash { get; set; }
    public string PasswordSalt { get; set; }
}

我有一个用于注册用户的服务方法,看起来像这样:

public void Register(User user, string planTextPassword)
{
    //Make sure the email address is not taken.
    bool emailIsTaken = IsEmailTaken(user.Email);

    if (emailIsTaken)
    {
        //What do I do here?
    }
    else
    {
        //Create the user.
    }
}

最后,我的控制器动作将它们捆绑在一起:

public ActionResult Signup(SignupViewModel signupViewModel)
{
    if (ModelState.IsValid)
    {
        _accountService.Register(Mapper.Map<SignupViewModel, User>(signupViewModel), signupViewModel.Password);
        _unitOfWork.Commit();
    }

    return View(signupViewModel);
}

正如您在我的服务方法中的注释中看到的,当服务级别验证失败时我该怎么办?正如this question 中所讨论的,我不应该抛出异常。但我不确定我是否遵循 Ryan 的建议,或者即使这仍然适用(即现在是否有更好的方法来处理 MVC 3 或其他可用的工具,如 Fluent Validation)。

就像我说的那样,我想我现在只能只见树木不见森林,但是在过去的两三个小时里我试图自己弄清楚,我想我可能会运气更好问一个问题。

提前致谢。

【问题讨论】:

    标签: asp.net-mvc validation asp.net-mvc-3


    【解决方案1】:

    我曾经尝试做 Ryan 所说的事情。他说的基本上是你的服务应该是这样的:

    public class TheService{
      ValidationResult Validate(YourType item);
      Save(YourType item);
    }
    

    用法是首先调用 Validate,如果 ValidationResult 成功,则调用 Save。 Save 将再次验证实体以确保您不会忘记验证它。不同的是,如果在 Save 调用 validate 时出现错误,则会抛出异常。

    我个人曾经这样做过一次,不会再这样做了。我认为仅仅抛出一个异常就可以让一切变得更加清晰,并且减少了需要维护的代码。

    要将错误信息返回给控制器,您需要创建自己的异常。它可能看起来像这样:

    public class RulesException : Exception{
       public IEnumerable<ErrorInfo> Errors {get;set;}
    }
    
    public class ErrorInfo{
      public string PropertyName {get;set;}
      public string ErrorMessage {get;set;}
    }
    

    沿着这些路线的东西是一个开始。为了更好的实现,请查看xVal的源代码

    注意:如果您使用异常,请尽量避免在循环内执行 try/catch 的地方编写代码。当涉及到异常时,这是要避免的最重要的事情,因为它们更昂贵,但与数据库调用相比,例如它很便宜。

    【讨论】:

    • 这是一个很好的答案。很高兴听到有人尝试了这两种方法,您的样本肯定会派上用场。
    【解决方案2】:

    如果您不想使用异常,除了让您的服务方法返回某种丰富的错误消息对象之外,您实际上没有其他选择。在链接帖子中的论点中,我唯一强烈同意的是异常(本身)不太可能导致良好的错误消息。他们为他们做的事情是他们很难忽视,所以你很可能意识到你有问题。

    此外,您无论如何都必须处理异常,因为即使您在服务代码中完全避免它们,您的代码也不是唯一可能导致抛出异常的东西。

    也就是说,不是让 Register 具有 void 返回类型,您可以返回一个可以表示成功或失败的类的实例,并且在失败的情况下有另一个列出错误的属性。这是有原则的事情——例如在 Haskell 等语言中很常见。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-06
      • 2020-09-27
      • 1970-01-01
      • 1970-01-01
      • 2014-02-19
      • 2017-10-19
      • 2016-10-17
      • 1970-01-01
      相关资源
      最近更新 更多