服务层验证

Jam*_*mes 14 validation asp.net-mvc asp.net-mvc-3

我正在尝试在我的应用程序中实现验证策略.我有一个MVC层,服务层,存储库和域POCO.现在在MVC层,我在我的viewmodels上使用数据注释来验证用户输入,允许我给用户快速反馈.在控制器中,我在使用automapper设置域对象之前调用ModelState.IsValid来检查输入.

这就是我的麻烦所在.我将我的域对象传递给需要根据我的业务规则验证它的服务,但是如何将验证错误传递回控制器?我找到的示例执行以下操作之一:

  • 在Service层中抛出异常并捕获Contoller.但这似乎是错误的,例外情况肯定是例外,我们应该返回一些有意义的东西.
  • 使用ModelStateWrapper并将ModelStateDictionary注入Service.但是这种方法最终会展现成循环依赖(控制器依赖于服务,服务依赖于控制器),这似乎是一个糟糕的代码味道.
  • 将验证方法添加到POCO.问题在于业务规则可能依赖于其他POCO对象,所以这肯定应该在可以访问所需表和对象的服务中完成.

我缺少一种更简单的方法吗?我已经看到很多关于此的问题,但除了上面提到的那些之外没有具体的解决方案.我认为服务中进行验证的任何方法都可以传回一些我可以在控制器中使用的键/值对象,但我不确定此策略是否会在以后出现问题.

Ian*_*dge 13

我认为非常优雅的方法是在您的服务上使用验证方法,该方法返回业务逻辑中的模型错误字典.这样,就没有将ModelState注入服务 - 服务只进行验证并返回任何错误.然后由控制器将这些ModelState错误合并回它的ViewData.

所以服务验证方法可能如下所示:

public IDictionary<string, string> ValidatePerson(Person person)
{
    Dictionary<string, string> errors = new Dictionary<string, string>();

    // Do some validation, e.g. check if the person already exists etc etc

    // Add model erros e.g.:
    errors.Add("Email", "This person already exists");
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在控制器中使用扩展方法将这些错误映射到ModelState,如:

public static class ModelStateDictionaryExtensions
{
    public static void Merge(this ModelStateDictionary modelState, IDictionary<string, string> dictionary, string prefix)
    {
        foreach (var item in dictionary)
        {
            modelState.AddModelError((string.IsNullOrEmpty(prefix) ? "" : (prefix + ".")) + item.Key, item.Value);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你的控制器将使用:

ModelState.Merge(personService.ValidatePerson(person), "");
Run Code Online (Sandbox Code Playgroud)