【问题标题】:Validation on ViewModels in ASP.NET MVC验证 ASP.NET MVC 中的 ViewModel
【发布时间】:2010-11-11 05:49:00
【问题描述】:

关于如何在 ASP.NET MVC 中实现验证的大多数技巧似乎都围绕着模型(在模型和控制器之间构建服务层或使用验证属性装饰模型的属性)。

在我的应用程序中,我使用 ViewModels 进行控制器和视图之间的所有通信。

我的登录页面有一个名为“LoginViewModel”的 ViewModel,并带有一个名为“EmailAddress”的属性。

当用户输入他们的电子邮件地址并单击提交时,此 ViewModel 会被填充并发送到控制器,在那里验证电子邮件地址。

它必须是有效的电子邮件地址,并且用户必须来自在系统中注册的域。

添加验证的便捷方法是什么?我应该将验证放在 ViewModel 本身吗?还是应该留在控制器中?

【问题讨论】:

    标签: asp.net-mvc validation viewmodel


    【解决方案1】:

    “我应该将验证放在 ViewModel 本身中吗?还是应该留在控制器中”我同意 Robert 的观点,但我会添加一个插件以实现额外的自动化。

    如果您查看xVal 之类的工具,您会发现常规验证(例如,必填字段、范围内的数字、匹配正则表达式的字符串)可以通过修饰数据类的字段来自动完成。事实上,xVal 可以自动编写 JavaScript 进行例行验证,以便在客户端执行。无需编写任何代码。更深入的验证(例如,该用户是否是在我们数据库中注册的域的成员?)发生在模型层本身的服务器端。

    使用 ViewModel 惯用语可能会给这个方案带来一些挑战。我目前的方法是将我的实体对象嵌入到我的视图模型中,例如

    public class Contact {
        [Required]
        string Name { get; set; }
    }
    
    public class ContactView {
        public Contact Contact { get; set; }
        public string SomeOtherViewProperty { get; set; }
    }
    

    然后在控制器中,更新模型时发生浅验证:

    UpdateModel(contactViewModel.Contact, "Contact");
    

    需要更多信息或更复杂计算的验证发生在模型层本身内部。

    另一种方法是不嵌入实体对象,而只是在两者之间映射各个字段。我最近发现了一个名为AutoMapper 的工具,它自动链接域和视图模型对象之间的字段。貌似应该支持这种验证方式,虽然我还没用过。

    【讨论】:

    • 好主意,基思!目前我有和你一样的策略——在 ViewModels 中嵌入模型。我想要的是,如果 Models 和 ViewModels 都可以以相同的方式实现验证,并且像 xVal 这样的 JS 框架可以与其中任何一个无缝协作。这将是最灵活的方式。我认为验证不应该只与模型相关。
    • 我也一直在使用带有嵌入式模型类的自定义视图模型,包括 xVal。但是,有时我需要我的视图模型只包含模型属性的一个子集。我目前正在寻找 Automapper 来映射这些模型。它工作正常,但我如何在那种情况下使用 xVal?如果元数据对象包含不属于视图模型的属性,则使用 MetaData 属性装饰 ViewModel 不起作用,因为 AssociatedMetadataTypeTypeDescriptionProvider 会抛出异常。如果您一直在使用 Automapper,我想知道您是如何解决这个问题的。
    【解决方案2】:

    NerdDinner tutorials 显示验证发生在模型的部分类(即 Linq to SQL 或实体框架)中。但由于您使用的是视图模型,您可以将验证逻辑放在那里。

    验证逻辑没有进入控制器。相反,它通过检查属性从控制器挂钩,即 ModelState.IsValid

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Dinner dinner) {
    
        if (ModelState.IsValid) {
    
            try {
                dinner.HostedBy = "SomeUser";
    
                dinnerRepository.Add(dinner);
                dinnerRepository.Save();
    
                return RedirectToAction("Details", new { id=dinner.DinnerID });
            }
            catch {
                ModelState.AddModelErrors(dinner.GetRuleViolations());
            }
        }
    
        return View(new DinnerFormViewModel(dinner));
    }
    

    完整的细节在这里:

    构建模型
    http://nerddinnerbook.s3.amazonaws.com/Part3.htm

    这里:

    ViewData 和 ViewModel
    http://nerddinnerbook.s3.amazonaws.com/Part6.htm

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2016-05-13
    • 1970-01-01
    • 1970-01-01
    • 2011-03-04
    • 1970-01-01
    • 2020-08-16
    相关资源
    最近更新 更多