【问题标题】:asp.net mvc validation while using viewmodel使用 viewmodel 时的 asp.net mvc 验证
【发布时间】:2011-12-13 13:15:44
【问题描述】:

最近我决定使用视图模型而不是 EF EntityObjects。 我确信 GET 请求不会有问题,但我想知道如何处理创建和更新操作。 我已经阅读了很多讨论,并决定我将采取行动 int this way。 但又出现了一个问题:

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
    {
        ...
}

【问题讨论】:

    标签: asp.net-mvc validation viewmodel


    【解决方案1】:

    如果您切换到 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; }
    }
    

    在您的发布操作中,您可以执行以下操作:

    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);
    }
    

    显然我保持它非常简单。 遵循这种模式肯定会在代码方面增加一点开销,但是必须在客户端(只是对输入的正式验证)和服务器端(正式和语义验证)都进行检查。我更喜欢在业务程序集中拥有所有语义,将正式检查留给 MVC 不显眼的验证引擎(在我看来只是一些 UI 糖,是的,我讨厌 Javascript)。

    通常我的业务对象使用 ViewModel 的属性,认为它们是只读的(只是用于防止错误注入的有用属性)并执行肮脏/繁重的工作。

    这可能不是所有事情的完美解决方案,但我注意到应用这种模式(并迫使团队的其他成员也这样做)会产生良好的代码库。 是的,我们离完美还很远,我想只编写一次语义和形式检查,但这就是网络现在的工作方式。

    如果您需要进一步的建议或者我完全误解了您的问题,请告诉我。

    PS:一旦你选择了一种模式,无论如何都要坚持下去。

    编辑:(长 cmets 是不行的)

    在构造函数中,我通常在需要更改的字段上应用映射,我尝试将 ViewModel 属性视为只读,以避免不必要的修改。

    我的IsValid() 方法只进行业务检查(例如,给定一个 ID,它会检查某个表中的真实存在,或者给定一个用户名检查他是否可以实际访问某些数据)。

    这只是 ViewModel 验证(对我来说只是语法 => 字符串是字符串,整数是整数,正数 >= 0,尊重字符串长度,满足范围等等)和真正的业务有效性(语义 => 一个用户可以访问一些数据,一个对象在应用程序范围内是有效的)。

    当然,业务验证层也可以很简单(或根本不存在),我更喜欢将它们分开以实现可重用性(通常我的业务逻辑在MVC 应用程序和WPF 应用程序之间共享)。这是一些额外的工作,但从长远来看,它会带来更好的回报,我可以在任何地方使用我复杂的业务逻辑。 (与 Banks 合作是最大的目标。仅在一个程序集中更改逻辑,例如添加对某事的新检查,并确信使用该程序集的每个应用程序都是最新的)。

    所以肯定是更多的额外工作,但我认为在最近花费几天时间进行维护/演进之前投入几个开发小时会更好。

    如今的编程似乎已被简化为一劳永逸的活动,(由于减少了时间/预算,或者仅仅是因为我们完成了我们的任务然后更换了员工),但是每行编码都需要某种形式的维护未来,所以最好保持物品有序和清洁,更倾向于易于维护而不是开发速度。

    【讨论】:

    • 正如我在构造函数 (MyBusinessObj BsnObj = new MyBusinessObj(Obj)) 中理解的那样,我需要将视图模型映射回域模型,并且在这里 (BsnObj.IsValid()) 手动调用 IValidatableObject 的 Validate()。你不觉得有很多不必要的动作吗?
    猜你喜欢
    • 1970-01-01
    • 2010-11-11
    • 2023-03-12
    • 1970-01-01
    • 2020-08-16
    • 2016-05-13
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    相关资源
    最近更新 更多