【问题标题】:ModelState.IsValid is false but should be trueModelState.IsValid 为假但应该为真
【发布时间】:2020-08-23 09:01:08
【问题描述】:

我有一个带有 AJAX 更新的 ASP.NET MVC 应用程序。除了创建“收据”之外,每个实体的 CRUD 操作都正常工作。当控制器点击ModelState.IsValid 时会出现问题,这会转化为假,而实际上它应该是真的。一步步调试了这么多次,该为真的时候总是假的。

我正在使用 Entity Framework 进行实体操作,这是从 SQL Server 数据库生成的代码:

public partial class Receipt
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Receipt()
    {
        this.Receipts1 = new HashSet<Receipt>();
        this.Seminars = new HashSet<Seminar>();
    }

    public int Id { get; set; }
    public System.DateTime IssueDate { get; set; }
    public Nullable<System.DateTime> DeliveryDate { get; set; }
    public Nullable<System.DateTime> PaymentDue { get; set; }
    public Nullable<short> CompanyId { get; set; }
    public Nullable<int> Number { get; set; }
    public Nullable<int> ClosedReceiptId { get; set; }
    public Nullable<decimal> ReturnedAmount { get; set; }
    public Nullable<short> ReturnTypeId { get; set; }

    public virtual Company Company { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Receipt> Receipts1 { get; set; }
    public virtual Receipt Receipt1 { get; set; }
    public virtual ReturnType ReturnType { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Seminar> Seminars { get; set; }
}

除此之外,我还有 ReceiptMetadata 用于注释和 [Required] 字段:

[MetadataType(typeof(ReceiptMetadata))]
public partial class Receipt
{
}

public class ReceiptMetadata
{
    [Required]
    public int Number { get; set; }

    [Required]
    [DisplayName("Issue Date")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:G}")]
    public DateTime IssueDate { get; set; }

    [Required]
    [DisplayName("Payment Due")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd.MM.yyyy}")]
    public DateTime? PaymentDue { get; set; }

    [DisplayName("Return amount")]
    [DisplayFormat(DataFormatString = "{0:c}")]
    public Nullable<decimal> ReturnedAmount { get; set; }
}

我在控制器中的Create函数如下:

[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult Create([Bind(Include = "Id,IssueDate,DeliveryDate,PaymentDue,CompanyId,Number")]Receipt receipt, int? seminarId)
{
    if (seminarId == null)
    {
        Response.StatusCode = (int)HttpStatusCode.BadRequest;
        return Json(new { Message = "ID is required" });
    }

    Seminar seminar = db.Seminars.Find(seminarId);

    if (seminar == null)
    {
        Response.StatusCode = (int)HttpStatusCode.BadRequest;
        return Json(new { Message = "Seminar doesn't exist" });
    }

    int receiptNumber = db.Receipts.Where(r => r.CompanyId == receipt.CompanyId && r.ClosedReceiptId == null && r.IssueDate.Year == DateTime.Now.Year).Count() + 1;
    receipt.Number = receiptNumber;
    receipt.IssueDate = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.Now, TimeZoneInfo.Local.Id, "Central European Standard Time");

    if (ModelState.IsValid)
    {
        try
        {
            db.Receipts.Add(receipt);
            db.SaveChanges();

            seminar.ReceiptId = receipt.Id;
            db.Entry(seminar).State = EntityState.Modified;

            db.SaveChanges();

            GeneratePDF(receipt.Id, receipt.ReceiptNumber, receipt.CompanyId.ToString());
            return Json(new { receipt.Id, receipt.PDFLink, Action = "Create", Message = "Receipt successfully added! -> " }, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(new { Message = ex.Message });
        }
    }

    Response.StatusCode = (int)HttpStatusCode.BadRequest;
    IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
    List<string> errorMessages = new List<string>();

    foreach (ModelError error in allErrors)
    {
        errorMessages.Add(error.ErrorMessage);
    }

    return Json(new { Message = errorMessages });
}

我得到的错误是

数字字段是必需的。

Number 字段明确填写为:

receipt.Number = receiptNumber;

IsValid 前几行。

有人可以帮忙吗?

编辑:这是调试的截图,modelstate 键完全错误:

【问题讨论】:

  • 我认为 IsValid 和整个 ModelState 的值是在您对控制器代码进行任何更改之前计算的。太晚了!
  • 我相信ModelState 会记录您发布数据时的模型状态。您应该将属性设为Nullable
  • 我担心的是,正如您从 ReceiptMetadata 中看到的那样,“IssueDate”也是必需的,并且放在数字之后,但不会出现任何错误。我用调试模式下的 ModelState 错误图像更新了主要问题,这很奇怪,并且显示错误的键,因为它们应该是“PaymentDue”、“IssueDate”和“Number”,而不是“CompanyId”或“seminarId”,这只是辅助属性

标签: c# asp.net ajax asp.net-mvc modelstate


【解决方案1】:

在输入您的操作时,ModelState 已经被评估(并且无效),设置“数字”属性不会再次评估模型。设置属性后,您可能必须通过编写以下代码手动将其从模型错误中删除:

ModelState.Remove("Number");

【讨论】:

  • 谢谢,这解决了我的问题。但我仍然想知道为什么我的 ModelState 键显示不正确,缺少我的元数据中必需的发布日期
  • IssueDate 在您的模型中是 DateTime,如果您使用调试器检查该值,它可能具有最小日期时间值:0001 年 1 月 1 日。听起来很奇怪,但如果您想将其设为必需并检查null 值,尝试将其更改为“日期时间?”
猜你喜欢
  • 1970-01-01
  • 2012-12-06
  • 2011-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多