C# 某些必填字段在ViewModel MVC3上不起作用

C# 某些必填字段在ViewModel MVC3上不起作用,c#,asp.net-mvc,validation,data-annotations,C#,Asp.net Mvc,Validation,Data Annotations,控制器操作: [AjaxRequestOnly, HttpPost, Authorize] public ActionResult AddCreditCard(CustomerCreditCardModelView cc) { if (!ModelState.IsValid) { Response.StatusCode = 400; return Content(Newtonsoft.Json.JsonConvert.Se

控制器操作:

 [AjaxRequestOnly, HttpPost, Authorize]
    public ActionResult AddCreditCard(CustomerCreditCardModelView cc) {
        if (!ModelState.IsValid) {
            Response.StatusCode = 400;
            return Content(Newtonsoft.Json.JsonConvert.SerializeObject(ModelState.Values.SelectMany(v => v.Errors).Select(e=>e.ErrorMessage)));
        }
        // .... do something ...        
    }
模型视图:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using CheckoutVC.CheckoutServiceReference;
using Newtonsoft.Json;

public class CustomerCreditCardModelView {

    [Display(Name = "Número")]
    [Required(ErrorMessage = "El Número es requerido")]
    [StringLength(20, MinimumLength = 12, ErrorMessage = "El número parece ser incorrecto")]
    [JsonIgnore, ScriptIgnore]
    public string CardNumber { get; set; }

    [Display(Name = "Código de seguridad")]
    [Required(ErrorMessage = "El Código de seguridad es requerido")]
    public string CardSecurityCode { get; set; }

    [Display(Name = "Nombre en la tarjeta")]
    [Required(ErrorMessage = "El Nombre en la tarjeta es requerido")]
    public string NameOnCard { get; set; }

    [Display(Name = "Dirección de cobro")]
    [Required(ErrorMessage = "La Dirección de cobro es requerida")]
    public string BillingAddress { get; set; }

    [Display(Name = "Mes de vencimiento")]
    [Required(ErrorMessage = "El Mes de vencimiento es requerido")]
    public int ExpirationMonth { get; set; }

    [Display(Name = "Año de vencimiento")]
    [Required(ErrorMessage = "El Año de vencimiento es requerido")]
    public int ExpirationYear { get; set; }

    [Display(Name = "Documento")]
    [Required(ErrorMessage = "El documento es requerido")]
    public string Document { get; set; }

    [Display(Name = "Tipo de tarjeta")]
    public int IdCreditCard { get; set; }

    public int IdCustomer { get; set; }
    public bool IsDeleted { get; set; }
    public int IdCustomerCreditCard { get; set; }
    public CustomerCreditCardModelView() {

    }
请求有效负载:

{"idCreditCard":1,"nameOnCard":"fdsa","billingAddress":"fdsa"}
请求-响应:

["El Número es requerido","El Código de seguridad es requerido","El documento es requerido"]
正如您所看到的,除了int ExpirationMonth和int ExpirationYear应该返回一个验证错误(必需)之外,其他一切都可以正常工作,但它们没有

实际上,modelstate只有6个键

是什么导致了这种行为?我希望expirationMonth和expirationYear考虑[Required]DataAnnotation属性

可以肯定的是,这里也发生了同样的事情:


编辑:阅读关于这个问题的评论,看看问题出在使用上,而不是我的案例。我包括了使用部分。

这可能是因为
ExpirationMonth
ExpirationYear
属性是整数值。Integer是值类型,因此它不能为null,默认值为0,从RequiredAttribute的角度来看,这是正确的

您可以做的是将类型从
int
更改为
int?
,使其可以为空

您的viewmodel:

public class CustomerCreditCardModelView {

    [Display(Name = "Número")]
    [Required(ErrorMessage = "El Número es requerido")]
    [StringLength(20, MinimumLength = 12, ErrorMessage = "El número parece ser incorrecto")]
    [JsonIgnore, ScriptIgnore]
    public string CardNumber { get; set; }

    [Display(Name = "Código de seguridad")]
    [Required(ErrorMessage = "El Código de seguridad es requerido")]
    public string CardSecurityCode { get; set; }

    [Display(Name = "Nombre en la tarjeta")]
    [Required(ErrorMessage = "El Nombre en la tarjeta es requerido")]
    public string NameOnCard { get; set; }

    [Display(Name = "Dirección de cobro")]
    [Required(ErrorMessage = "La Dirección de cobro es requerida")]
    public string BillingAddress { get; set; }

    [Display(Name = "Mes de vencimiento")]
    [Required(ErrorMessage = "El Mes de vencimiento es requerido")]
    public int? ExpirationMonth { get; set; }

    [Display(Name = "Año de vencimiento")]
    [Required(ErrorMessage = "El Año de vencimiento es requerido")]
    public int? ExpirationYear { get; set; }

    [Display(Name = "Documento")]
    [Required(ErrorMessage = "El documento es requerido")]
    public string Document { get; set; }

    [Display(Name = "Tipo de tarjeta")]
    public int IdCreditCard { get; set; }

    public int IdCustomer { get; set; }
    public bool IsDeleted { get; set; }
    public int IdCustomerCreditCard { get; set; }
    public CustomerCreditCardModelView() {

    }
}

另一种方法是使验证更加严格,从名称
ExpirationMonth
ExpirationYear
我认为最适合您

当您尝试验证时,屏幕上是否隐藏了一些内容?服务器端验证不起作用。如果我在请求有效负载中添加类似expirationMonth:null的内容,则数据批注会起作用。这太疯狂了。它们是int是有原因的,如果我不发送请求,我希望有一个无效的验证。这不是问题所在。实际上,问题在于服务器端验证即使在没有定义这些值的情况下也会接受输入。这就是问题所在。0是有效的整数。模型验证用于验证模型。这与请求无关,这是另一种责任。智力?当ModelBinder基于请求创建对象时(如果请求不包含该属性的任何信息),该属性将为null。好的,因此对所需int的服务器端验证甚至不会检查模型是否收到int值。所以你可以很容易地用小提琴手通过模型验证。。。听起来有点糟糕的设计。好的,我做了一点实验,发现它是如何工作的,看起来像是模型绑定器在测试请求中的任何数据注释之前做了一个新对象(当然是默认值)。我明白为什么会这样,但在我看来还是不太好,而且有点违反直觉。在我看来,你不能为一个int型的巨大安全漏洞做必要的数据注释仍然是很可怕的。爱你的人!您的回答解决了我的“错误”: