服务层验证

时间:2011-12-13 10:41:38

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

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

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

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

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

2 个答案:

答案 0 :(得分: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");
}

然后你可以在控制器中使用扩展方法将这些错误映射到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);
        }
    }
}

然后您的控制器将使用:

ModelState.Merge(personService.ValidatePerson(person), "");

答案 1 :(得分:2)

作为Ian建议创建中间字典的替代方法,您也可以使用接受函数的验证器来执行此操作。

e.g。在服务层:

public void ValidateModel(Customer customer, Action<string, string> AddModelError)
{
  if (customer.Email == null) AddModelError("Email", "Hey you forgot your email address.");
}

然后在您的控制器中,您只需一次通话即可验证:

myService.ValidateModel(model, ModelState.AddModelError);

或者说您想在控制台应用中使用验证器而无法访问ModelStateDictionary,您可以这样做:

errors = new NameValueDictionary();
myService.ValidateModel(model, errors.Add);

这两项工作都是因为 ModelStateDictionary.AddModelError()NameValueDictionary.Add() 匹配Action<string, string>的方法签名。