假设我有一个看起来像这样的控制器:
public class ProjectController : Controller
{
private IProjectRepository projectRepository;
public ProjectController()
{
DBContext context = new DBContext();
this.projectRepository = new ProjectRepository(context);
}
public ActionResult Create(Project project)
{
if (ModelState.IsValid)
{
// do whatever
}
else
{
return View(project);
}
}
}
并且假设这是一个看起来像这样的模型的控制器:
public class Project : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// this is where I would like to add code
}
}
我的问题是:验证代码中是否真的没有办法在控制器上引用projectRepository对象?是的,我可以在技术上为控制器上的Create()函数添加准验证,在那里进行检查,并直接添加错误 - 但在实际情况中,有许多操作都会执行相同的验证,与您尝试创建(或编辑,复制或其他任何)的模型紧密相关。但是它与模型和绑定到同一模型的其他现有实例,只有控制器知道如何查询。有没有办法解决这个问题?
(目标是检查验证中的当前模型对象是否与已存在的模型对象不同;我对其他如何做的建议持开放态度,它看起来很明显 应该是标准验证代码的工作,使用IValidatableObject或使用ValidationAttribute。但我不是.net MVC验证的专家,或者就此而言,.net MVC。)
谢谢!
答案 0 :(得分:3)
IValidatableObject
属于DataAnnotations
命名空间。在我看来,Data Annotations非常适合输入验证。当他们开始应用复杂的业务规则时,您的域模型的有效性取决于其他域模型的状态。
当发生这种情况时,引入服务层。将所有业务规则放在那里,并允许服务调解模型之间的对话。在一天结束时,服务应该是您与模型通信的接口。
这是我经常对自己说的话,“嘿,你的应用程序现在已经达到'中等复杂度'阶段”! :)
可以在此处找到较旧但仍然相关的教程:http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validating-with-a-service-layer-cs
答案 1 :(得分:1)
国际海事组织,有一个公约问题在起作用。控制器返回到客户端的模型是 ViewModel ,而不是实体。当考虑哪些对象具有依赖对象的知识时,这就起到了作用。
存储库处理模型(实体),控制器处理 ViewModels 。 ViewModel实际上只是一堆数据和格式,因此在ViewModel上设置级验证没有意义。
并且真的希望业务层或存储库执行集级验证,而不是模型本身。您可以在模型创建时设置对模型库的引用,并让模型调用存储库进行集级验证。但是当你想要克隆或反序列化实体时,这就成了问题。
顺便说一下, EntityFramework 通过允许Attach
断开连接的实体来解决这些问题。您可能希望使用EF而不是存储库模式。
但是对于您的直接问题,我不会尝试在实体或视图模型中执行设置级验证。
答案 2 :(得分:1)
您最好放置validation in the service layer
在线脚手架工具CamoteQ以这种方式生成模型验证码,这是自学的一个很好的参考。