ASP.NET MVC:如何让我的业务规则验证冒泡到表示层?

时间:2011-01-28 01:42:18

标签: c# asp.net-mvc

对于我的每个业务实体,我都有相应的视图模型。

我有一个通用的CRUD控制器,其工作原理如下:

    [HttpPost]
    public virtual ActionResult Create(TViewModel model, int? id)
    {
        // Validate input
        if (!ModelState.IsValid)
            return Json(Failure(createView, model.SelectLists(repository)));

        // Prepare Model
        var entity = new TModel();

        // Add to repository
        UpdateModel(entity);
        repository.Add(entity);
        repository.Save();
        return Json(CreateSuccess(entity));
    }

我在视图模型属性上使用数据注释,这对于简单的输入验证非常有用。

现在我有一个案例,我想确保不会偶然创建重复记录。

我的第一直觉是将此逻辑放在存储库的Add方法中。这个实现很简单,但是如何让存储库添加模型状态错误并将一些有用的信息返回给用户?我觉得必须有一个解决方案,但我没有太多的运气搜索。

感谢您的帮助!

3 个答案:

答案 0 :(得分:3)

我会使用例外。

  • 如果enity加倍,则在Add方法中抛出自定义应用程序异常。
  • 在try块中包装Add方法以在Create方法中捕获此特定异常。
  • 根据catch块中的异常数据添加模型状态错误

    try
    {
        repository.Add(entity);
    }
    catch(MyRepositoryException ex)
    {
        ViewData.ModelState.AddModelError(ex.Key, ex.Value.ToString(), ex.Message)
    }
    
    if (!ModelState.IsValid)
                return Json(Failure(createView, model.SelectLists(repository)));
    

答案 1 :(得分:1)

我讨厌回答我自己的问题,但我想在找到别的东西时偶然发现了我正在寻找的答案:

http://nerddinnerbook.s3.amazonaws.com/Part3.htm

看起来是回归基础评论的时候了!我应该想回去看看我的第一个教程,因为在我刚开始的时候,我无法吸收所有内容。

本教程的第3部分讨论了如何实现域模型验证,该验证返回带有属性名称和错误消息字符串的错误,这些字符串将添加到控制器的ModelState中,从而允许进行此类验证:

if (ModelState.IsValid) {

    try {
        dinner.HostedBy = "SomeUser";

        dinnerRepository.Add(dinner);
        dinnerRepository.Save();

        return RedirectToAction("Details", new{id=dinner.DinnerID});
    }
    catch {
        ModelState.AddModelErrors(dinner.GetRuleViolations());
    }
}

我不知道我是否喜欢为违反业务规则而引发异常的想法,但基本模式对我的项目很有用。希望这有助于其他人!

答案 2 :(得分:1)

您的方法的替代方法是使用ModelStateWrapper实施IValidationDictionary的想法。它基本上解耦了modelState,但仍然允许您的存储库/服务与错误字典交互。这种方式错误处理都是通过接口完成的,不需要引用任何特定于MVC的数据对象。

这里有一篇很好的文章:http://www.asp.net/mvc/tutorials/validating-with-a-service-layer-cs,但基本的想法是:

1)在控制器初始化期间将ModelStateWrapper的实例传递给存储库:

public MyController() 
{
    repository = new MyRepository(new ModelStateWrapper(this.ModelState));
}

2)在存储库中添加错误:

_validatonDictionary.AddError("Name", "Name is required.");

3)处理你通常在控制器中出现的错误:

if (!repository.Save())
    return View();