ASP.NET MVC模型验证在ViewModel上无法正常工作

6
我有一个ViewModel,里面包含一个Model和一些额外的属性。对于Model和属性都有验证,但是在执行时,只会检查Model上的验证,而忽略了属性上的验证。
Model:
 [MetadataType(typeof(Customer_Validation))]
 public partial class Customer
 {
 }

 public class Customer_Validation
 {
     [Required(ErrorMessage="Please enter your First Name")]
     public string FirstName { get; set; }

     [Required(ErrorMessage = "Please enter your Last name")]
     public string LastName { get; set; }

     [Required(ErrorMessage = "Sorry, e-mail cannot be empty")]
     [Email(ErrorMessage="Invalid e-mail")]
     public string Email { get; set; }
 }

视图模型
 public class RegisterViewModel
 {
     public Customer NewCustomer { get; private set; }

     [Required(ErrorMessage="Required")]
     public string Password { get; private set; }

     public RegisterViewModel(Customer customer, string password)
     {
         NewCustomer = customer;
         Password = password;
     }
 }

控制器
public ActionResult Create()
{
     Customer customer = new Customer();    
     RegisterViewModel model = new RegisterViewModel(customer, "");    
     return View(model);
}

[HttpPost]
public ActionResult Create(Customer newCustomer, string password)
{
     if (ModelState.IsValid)
     {
         try
         {
             // code to save to database, redirect to other page
         }
         catch
         {
             RegisterViewModel model = new RegisterViewModel(newCustomer, password);
             return View(model);
         }
     }
     else
     {
         RegisterViewModel model = new RegisterViewModel(newCustomer, password);
         return View(model);
     }
}

视图(View)

@using (Html.BeginForm())
 {
  <table>
   <tr>
    <td>First Name:</td>
    <td>@Html.TextBoxFor(m => m.NewCustomer.FirstName)</td>
    <td>@Html.ValidationMessageFor(m => m.NewCustomer.FirstName)</td>
   </tr>
   <tr>
    <td>Last Name:</td>
    <td>@Html.TextBoxFor(m => m.NewCustomer.LastName)</td>
    <td>@Html.ValidationMessageFor(m => m.NewCustomer.LastName)</td>
   </tr>
   <tr>
    <td>E-mail:</td>
    <td>@Html.TextBoxFor(m => m.NewCustomer.Email)</td>
    <td>@Html.ValidationMessageFor(m => m.NewCustomer.Email)</td>
   </tr>
   <tr>
    <td>Password:</td>
    <td>@Html.TextBoxFor(m => m.Password)</td>
    <td>@Html.ValidationMessageFor(m => m.Password)</td>
   </tr>
  </table>

  <input type="submit" value="Register" />
 }

如果我提交表单时将密码字段留空,它会让我通过。如果我将客户字段留空,则会显示错误(除了密码字段)。
2个回答

13

这是正常的。您的POST控制器操作将 Customer 作为参数而不是视图模型。验证由模型绑定器执行,因此当模型绑定器尝试从请求参数中绑定Customer对象时,它将调用验证。如果您希望在此视图模型上执行验证,则POST操作需要将视图模型作为参数。目前,在post操作内您对此视图模型所做的所有事情都只是调用构造函数,而调用构造函数不会触发任何验证。

因此,您的POST操作应更改为:

[HttpPost]
public ActionResult Create(RegisterViewModel newCustomer)
{
     if (ModelState.IsValid)
     {
         // code to save to database, redirect to other page
     }
     else
     {
         return View(newCustomer);
     }
}

注意,你不需要将密码作为第二个操作参数传递,因为它已经是你的视图模型的一部分。


那听起来很合理,可以帮助我修复它。在找到使用模型验证的最佳解决方案之前,我将单独在控制器中进行其他属性验证。非常感谢。 - Nestor
你如何使View将ViewModel传递给Post控制器?我之前尝试过,但出现了“可空参数”错误,因为表单接收到ViewModel,但在回传时会将其拆分为ViewModel中的每个模型,因此无法匹配Post控制器上的签名,然后控制器将null设置为ViewModel参数,这迫使我在Post控制器中将每个模型作为单独的参数获取,而不是一个ViewModel的单一参数。 - Nestor
@Nestor,要使视图将ViewModel传递给控制器,您可以在此视图中包含一个<form>,并在其中放置与将要传递的ViewModel属性对应的文本字段。请记住,只有请求中发送的内容才会绑定到ViewModel。 - Darin Dimitrov
我的意思是,像我的示例一样的ViewModel,其中包含一个Customer对象和一个字符串Password,到目前为止,我无法让View将这样的内容传递到一个单独的ViewModel中,换句话说,像这样的复杂模型不能被View绑定,只能绑定内部的Customer对象模型和字符串密码。如果我像Create(ViewModel model)这样编写我的Post控制器,我会得到一个“可空参数”错误,只有Create(Customer newCustomer, string password)才可以。 - Nestor

0

我认为这是因为您密码属性的setter被设置为private set。您其余客户字段的所有setter都是公共setter。当属性没有setter时,不需要进行有效值的检查。


当模型被绑定时,构造函数会被调用,构造函数负责设置那些私有属性,不需要从类外部访问这些属性。原因就像Darin所说的,只有Model被调用,而不是ViewModel,因此没有为ViewModel绑定,因此不触发验证。 - Nestor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接