ASP.NET MVC模型验证打破了MVC规则?

时间:2011-05-18 14:09:25

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

使用ASP.NET MVC,我有一个模型,我附加了属性,以便我可以使用MVC模型绑定验证,但是这不会破坏MVC的规则,您将属于View的项目放入模型中?我希望自己不是为了变得聪明,但我对其他人的意见感到好奇。

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

3 个答案:

答案 0 :(得分:10)

是。这就是为什么你应该使用ViewModels。

答案 1 :(得分:10)

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

但最好使用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

进行验证。

答案 2 :(得分:1)

严格意义上是否违反了MVC,是的,可能。是否存在违反此规定无害的时候?当然。但是,有一些机制可以帮助您解决问题。

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

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%的情况下都不会起作用,或者至少我可以弄清楚如何做我需要的东西,但是地图服务可以很容易地定义从左到右的自定义地图。