【问题标题】:ASP.NET MVC model validation breaks MVC rule?ASP.NET MVC 模型验证违反 MVC 规则?
【发布时间】:2011-08-28 02:44:37
【问题描述】:

使用 ASP.NET MVC,我有一个模型,我将属性附加到它,以便我可以使用 MVC 模型绑定验证,但是 这不违反 MVC 规则,您将属于视图的项目放入模型中的位置?我希望我不要自作聪明,但我很好奇别人的意见。

public class Payments
{
    [DataType(DataType.Text)]
    [DisplayFormat(NullDisplayText="")]
    [Display(Name="Payment Id")]
    [Required(ErrorMessage="Required")]
    public int PaymentId { get; set; } //todo: make this into a dropdown

    [DataType(DataType.Text)]
    [Display(Name="Bill Name")]
    [Required(ErrorMessage = "Required")]
    public string PaymentName { get; set; }

    [DataType(DataType.Date)]
    [Display(Name="Date to Post Payment")]
    [Required(ErrorMessage = "Required")]
    public DateTime PaymentDate { get; set; }

    [DataType(DataType.Currency)]
    [Range(0, 922337203685477.5807)]
    [Required(ErrorMessage = "Required")]
    public double PaymentAmount { get; set; }
}

【问题讨论】:

    标签: asp.net asp.net-mvc view model model-validation


    【解决方案1】:

    您可以但不必将这些验证属性放入您的模型中。

    但最好使用 ViewModel:

    public class PaymentsViewModel
    {
        [DataType(DataType.Text)]
        [DisplayFormat(NullDisplayText="")]
        [Display(Name="Payment Id")]
        [Required(ErrorMessage="Required")]
        public int PaymentId { get; set; } //todo: make this into a dropdown
    
        [DataType(DataType.Text)]
        [Display(Name="Bill Name")]
        [Required(ErrorMessage = "Required")]
        public string PaymentName { get; set; }
    
        [DataType(DataType.Date)]
        [Display(Name="Date to Post Payment")]
        [Required(ErrorMessage = "Required")]
        public DateTime PaymentDate { get; set; }
    
        [DataType(DataType.Currency)]
        [Range(0, 922337203685477.5807)]
        [Required(ErrorMessage = "Required")]
        public double PaymentAmount { get; set; }
    }
    

    在你的视图中,而不是:

    @model YourProject.Models.Payments
    

    你使用:

    @model YourProject.Models.PaymentsViewModel
    

    用于验证。

    【讨论】:

    • 放置 ViewModel 类的最佳位置在哪里?假设您有两个解决方案:MyProject.UI 和 MyProject.Models,Payment 类是 MyProjects.Models.Payment。把 ViewModel 放在 MyProject.UI.Models.PaymentViewModel 还是 MyProject.Models.PaymentViewModel 更好?
    • @WeekendWarrior:实际上放在哪里并不重要。我有制作 2 个文件夹的习惯:Models 和 ViewModels 并把它们放在那里。
    • 你的模型是什么样的?看起来很像这里的语义论点,尽管这是一个简单的例子。
    • 老实说,所谓的 ViewModel 是准确的模型,可以从实体构建。但是...实体/表格记录!=模型
    【解决方案2】:

    它是否违反了严格意义上的 MVC,是的,可能。有没有违反它没有害处的时候?当然。但是,有一些机制可以帮助您解决问题并将这些问题分开。

    您可以在视图中使用持久化的域对象并针对它们进行验证,但是当您的视图开始变得复杂时,ViewModel 就成为必需品。对于死的简单域模型或仅查看视图(不是编辑/创建),我有时会稍作修改并将它们作为复合对象的一部分发送到视图中:

    class MyViewModel
    {
        public MyDomainModel DomainObj;
        public int OtherViewInfo;
    }
    

    但是,对于创建和编辑场景,ViewModel 要好得多。它们允许您完全控制发送到视图和来自视图的数据。

    如果您使用的是 EF 4.1 和 CodeFirst,那么是的,您最终会在域和 ViewModel 之间出现一些属性和属性的重复。这是不可避免的,但可以让您灵活地针对视图进行不同的验证。

    我发现在实际保存域对象时在控制器中增加一层保护很有用,以防我错过了视图中的某些验证:

    public class MyController : Controller
    {
        [HttpPost]
        public ActionResult Edit(int id, MyViewModel model)
        {
            try
            {
                ...Do stuff, check ModelState.IsValid...
                _context.SaveChanges()
            }
            catch (DbEntityValidationException dbEx)
            {
                // Catch any validation errors on the domain that weren't duplicated
                // in the viewmodel
                ModelState.AddModelError("Form", dbEx);
            }
    
            return View(model);
        }
    }
    

    下一个要问的问题是如何在域模型和 ViewModel 之间进行映射。有许多策略和工具 - AutoMapperValueInjecter(是的,拼写错误)。就个人而言,我一直在使用 ValueInjecter,但如果你设置了一个映射层,你可以同时尝试。我发现这两种情况在 100% 的情况下都不起作用,或者至少我可以弄清楚如何做我需要的事情,但是地图服务可以轻松定义自定义的从左到右的地图。

    【讨论】:

      【解决方案3】:

      是的。这就是您应该使用 ViewModels 的原因。

      【讨论】:

      • 我不理解 MVC 上下文中的“ViewModel”这个词。我理解“MVC”是为模型-视图-控制器打磨的。我理解“MVVM”代表模型-视图-视图模型。那么,如果我们在谈论 MVC,那么为什么要谈论 ViewModel?
      • 是的,这个答案不正确,也违反了 MVC... Model != Entity
      • 根据手头的技术堆栈的上下文量身定制答案和讨论非常重要。模型和视图模型在讨论 ASP.NET MVC 时有意义,但在阅读 Martin Fowler 时则不然。 MVC 的原始概念几乎与几乎所有语言在网络上使用的实际实现完全不同。
      猜你喜欢
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-05
      • 2011-12-24
      • 1970-01-01
      • 2010-11-18
      相关资源
      最近更新 更多