don*_*tta 5 validation asp.net-mvc viewmodel
最近我决定使用视图模型而不是 EF EntityObjects。我确信 GET 请求不会有问题,但我想知道如何处理创建和更新操作。我已经阅读了很多讨论并决定我会以这种方式行事。但出现了另一个问题:
1) 当我使用带有注释的 EF EntityObjects 时,验证逻辑存储在一个地方,但是如果我在不同的项目中有不同的视图模型,那么我将不得不复制验证规则。这不是违反了 DRY 原则吗?
2)我已经阅读了几篇关于视图模型和验证的帖子,其中人们建议验证视图模型中的输入和域模型中的业务规则,但我无法意识到如果我的操作将视图模型作为参数,我如何调用域模型中定义的验证:
public class MyDomainModel : IValidatableObject
{
public string Title;
// validation of business rules
}
public class MyViewModel
{
[Required]
public string Title;
}
public ActionResult Edit(MyViewModel item)
{
if (ModelState.IsValid) // MyViewModel's rules are validated not MyDomainModel's
{
...
}
Run Code Online (Sandbox Code Playgroud)
如果您切换到 ViewModels,您应该让框架通过 ViewModel 类中的 DataAttributes 执行验证。这只是对输入的正式检查,然后您应该根据您的业务规则进行验证(有时仅使用数据注释是不可能覆盖所有场景的),如果出现错误,请将它们添加到模型状态。
例子:
public class MyViewModel
{
[Required]
[StringLength(20)]
[RegularExpression("whatever")]
public string Foo { get; set; }
[Required]
public int Bar { get; set; }
public bool AFlagNotModifiableButImportant { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在您的发布操作中,您可以执行以下操作:
public ActionResult Sample (MyViewModel Obj)
{
if (!ModelState.IsValid) {
return View(Obj);
}
// Complex business logi checks in here
MyBusinessObj BsnObj = new MyBusinessObj(Obj);
if (!BsnObj.IsValid()) {
ModelState.AddModelError(string.Empty, "A veery bad error");
return View(Obj);
}
// Perform Heavy Business Logic which creates a new ViewModel (eg. setting the flag property in order to show something important at view level)
MyViewModel NewOne = BsnObj.DoIt();
// Return a view with the new Model (can be whatever you want)
return View(NewOne);
}
Run Code Online (Sandbox Code Playgroud)
显然,我保持非常简单。遵循这种模式肯定会在代码方面增加一点开销,但是必须在客户端(只是对输入的正式验证)和服务器端(正式和语义验证)都进行检查。我更喜欢在业务程序集中拥有所有语义,将正式检查留给 MVC 不显眼的验证引擎(在我的视图中只是一些 UI 糖,是的,我讨厌 Javascript)。
通常我的业务对象使用 ViewModel 的属性,将它们考虑为只读(只是防止错误注入的有用的那些)并完成肮脏/繁重的工作。
这可能不是所有事情的完美解决方案,但我注意到应用这种模式(并强制团队的其他成员也这样做),会产生一个好的代码库。是的,我们离完美还很远,我只想写一次语义和形式检查,但这就是网络现在的工作方式。
如果您需要进一步的建议,或者我是否完全误解了您的问题,请告诉我。
PS:一旦你选择了一种模式,无论如何都要坚持下去。
编辑:(长评论是不,不)
在构造函数中,我通常在需要更改的字段上应用映射,我尝试将 ViewModel 属性视为只读,以避免不必要的修改。
我的IsValid()方法只保存业务检查(例如,给定一个 ID,它检查某个表中的真实存在,或者给定一个用户名,检查他是否可以实际访问某些数据)。
它只是 ViewModel 验证(对我来说只是语法 => 字符串是字符串,整数是整数,正数是 >= 0,字符串长度得到遵守,范围得到满足等等)和实际业务有效性(语义=>一个用户可以访问一些数据,一个对象在应用程序的范围内是有效的)。
当然,业务验证层也可以很简单(或者根本不存在),我更喜欢将它们分开以实现可重用性(通常我的业务逻辑在MVC应用程序和WPF应用程序之间共享)。这是一些额外的工作,但从长远来看,它的回报更高,我可以在任何地方使用我的复杂业务逻辑。(与 Banks 合作,这是最大的目标。仅在一个程序集中更改逻辑,例如对某事添加新检查,并确信使用该程序集的每个应用程序都是最新的)。
所以肯定是更多的额外工作,但我认为最好在开发前投入几个小时而不是最近浪费几天进行维护/改进。
如今,编程似乎已简化为一劳永逸的活动,(由于减少时间/预算或仅仅因为我们完成任务然后更换员工),但编码的每一行,将来都需要某种维护,所以最好保持秩序和清洁,更喜欢维护方便而不是开发速度。