【问题标题】:Invalid Model State with ViewModel - C# ASP.NET COREViewModel 的模型状态无效 - C# ASP.NET CORE
【发布时间】:2021-08-12 08:09:28
【问题描述】:

希望是一个基本问题,我为联系人创建了一个“创建”页面,该页面创建了系统中所有客户的列表。我使用 ViewModel 来执行此操作,这很好。但是现在在客户模型上,我已将 CustomerName 字段指定为必填项,这导致 ModelState.IsValid 为假,我无法弄清楚原因。

客户

public class Customer
    {
        public int CustomerId { get; set; }
        [Required]
        [Display(Name = "Customer Name")]
        public string? CustomerName { get; set; }
        public ICollection<Contact> Contacts { get; set; }
        public ICollection<Job> Jobs { get; set; }
    }

联系方式

public class Contact
    {
        public int ContactId { get; set; }
        [Required]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }
        [Required]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
        [Display(Name = "Email Address")]
        public string EmailAddress { get; set; }
        public string Telephone { get; set; }
        public Customer Customer { get; set; }
    }

视图模型

    public class ContactDetailViewModel
    {
        public Contact Contact { get; set; }
        public Customer Customer { get; set; }
        public List<SelectListItem> Customers { get; set; }
    }

表格

        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Contact.FirstName" class="control-label"></label>
                <input asp-for="Contact.FirstName" class="form-control" />
                <span asp-validation-for="Contact.FirstName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Contact.LastName" class="control-label"></label>
                <input asp-for="Contact.LastName" class="form-control" />
                <span asp-validation-for="Contact.LastName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Contact.EmailAddress" class="control-label"></label>
                <input asp-for="Contact.EmailAddress" class="form-control" />
                <span asp-validation-for="Contact.EmailAddress" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Contact.Telephone" class="control-label"></label>
                <input asp-for="Contact.Telephone" class="form-control" />
                <span asp-validation-for="Contact.Telephone" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Customer.CustomerName" class="control-label"></label>
                <select class="form-control dropdown" asp-for="Customer.CustomerId" asp-items="@Model.Customers">
                    <option></option>
                </select>
                <span asp-validation-for="Customer.CustomerId" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>

控制器

public async Task<IActionResult> Create([Bind("ContactId,FirstName,LastName,EmailAddress,Telephone")] Contact contact, ContactDetailViewModel contactDetailViewModel)
        {
            contact.Customer = await _context.Customers.FirstOrDefaultAsync(c => c.CustomerId == contactDetailViewModel.Customer.CustomerId);
            //Has to be a better way of doing this??? Why is it faling without... 06/03/2021
            //ModelState.Remove("Customer.CustomerName");

            if (ModelState.IsValid)
            {
                _context.Add(contact);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(contact);
        }

如果我不包括 ModelState.Remove("Customer.CustomerName");然后它不起作用。但是我不想对 CustomerName 做任何事情,因为我只想将 Contact.Customer 更新为“新”选定的客户。

谢谢!

【问题讨论】:

  • 你的Customer.CustomerName 根本没有绑定,你绑定的是Customer.CustomerId :)。所以客户端验证甚至通过了。 CustomerName 的验证错误也适用于 CustomerId

标签: c# .net-core asp.net-core-mvc


【解决方案1】:

你的班级有错误。将 CustomerId 添加到联系人:

public class Contact
    {
        public int ContactId { get; set; }
        [Required]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }
        [Required]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
        [Display(Name = "Email Address")]
        public string EmailAddress { get; set; }
        public string Telephone { get; set; }
        public int  CustomerId { get; set; }
        public virtual  Customer Customer { get; set; }
    }

并修复视图:

<div class="form-group">
                <label asp-for="Customer.CustomerName" class="control-label"></label>
                <select class="form-control dropdown" asp-for="Contact.CustomerId" asp-items="@Model.Customers">
                    <option></option>
                </select>
                <span asp-validation-for="Contact.CustomerId" class="text-danger"></span>
            </div>

您也可以修复操作:


 contact.Customer = await _context.Customers.FirstOrDefaultAsync(c => c.CustomerId == contactDetailViewModel.Contact.CustomerId);

但它是一个冗余代码。您根本不需要此代码,因为您可以在没有此代码的情况下保存联系人。

您还需要通过添加 CustomerId 来修复绑定:

public async Task<IActionResult> Create([Bind("ContactId, CustomerId, FirstName,LastName,EmailAddress,Telephone")] Contact contact, ContactDetailViewModel contactDetailViewModel)

顺便说一下,您将整个客户包含在模型中仅用于

  <label asp-for="Customer.CustomerName" class="control-label"></label>

您可以将 Customer 属性保留为 null 并使用以下代码:

  <label asp-for="Contact.CustomerId" class="control-label"> Customer </label>

【讨论】:

  • 完美,非常感谢。我还必须对 Create 操作上的 LINQ 查询进行更改以使用 Contact.CustomerId 而不是 Customer.ContactId 但我相信这没问题?
  • 是的。我更新了我的答案。如果对您有帮助,请不要忘记接受答案。否则它将立即被鬣狗投票否决。
  • @DanielHill 奇怪的是这段代码对你有用,它甚至与CustomerName必需值 无关。当然,您需要的可能是CustomerId,但只要您的视图模型将CustomName 作为必需,该值也应该被绑定。所以不要告诉我这个&lt;label asp-for="Customer.CustomerName" 是绑定CustomerName 的东西——它只是一个标签。再次,请确认您实际删除应用于CustomerName[Required] - 否则无法正常工作。我觉得这很混乱。
  • @Hopeless Contact 实例被保存而不是客户实例。 CustomerName 与此无关,因为 Contact 只有从下拉列表中选择的 CustomerId。
  • @Sergey 你确定吗?再次仔细查看 OP 问题中的 Customer 类。你看到[Required] 应用在CustomerName 上了吗?这个视图模型ContactDetailViewModel 是绑定的(在Create 方法中),这意味着整个视图模型的图被绑定,包括ContactDetailViewModel.Customer。因此,如果 CustomerName 未绑定,则验证将失败(与他在问题中描述的完全一样)。我没有看到你甚至提到过他为什么会出现这个错误。为什么?你现在能解释一下吗?
猜你喜欢
  • 2019-06-03
  • 1970-01-01
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
  • 1970-01-01
  • 2018-03-22
  • 2022-11-08
  • 1970-01-01
相关资源
最近更新 更多