You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 6中Html.DropDownListFor引发NullReferenceException问题

问题:创建交易时出现NullReferenceException异常

我有Customer和Deals两个类,客户与交易是外键关联关系。为了让用户通过下拉列表选择发起交易的客户,我创建了包含客户SelectListItem集合和Deals实例的CreateDealVM视图模型,更新了DealController中的Create方法,但创建交易时抛出以下异常:

System.NullReferenceException HResult=0x80004003 Message=未将对象引用设置到对象的实例。

ViewModel代码

public class CreateDealVM
{
    public Deals deal { get; set; }
    public IEnumerable<SelectListItem> selectedCustomer { get; set; }
    public int selectedCustomerId { get; set; }
}

DealController方法代码

public IActionResult Create()
{
    Deals deal = new Deals();
    List<Customer> customerList = _context.Customers.ToList();
    CreateDealVM vm = new CreateDealVM();
    vm.selectedCustomer = new SelectList(customerList, "customerId", "customerName");
    vm.deal = deal;
    return View(vm);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateDealVM vm)
{
    if (ModelState.IsValid)
    {
        try
        {
            vm.deal.customer =_context.Customers.Find(vm.selectedCustomerId); 
            _context.Deals.Add(vm.deal);
            _context.SaveChanges();
            return RedirectToAction("Index");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        return View(vm);
    }
    return View();
}

Deal模型类代码

namespace MyShop.Models
{
    [Table("Deals")]
    public class Deals
    {
        [Key]
        [Display(Name = "ID")]
        public int dealId { get; set; }

        [ForeignKey("Customer")]
        [Display(Name = "Customer")]
        public Customer customer { get; set; }

        [Display(Name = "CustomerName")]
        public string? parentCustomerName { get; set; }
        
        [Display(Name = "product")]
        public DealTypeEnum product { get; set; }
        [Display(Name = "Date")]
        public DateTime saleDate { get; set; }
        [Display(Name = "Quantity")]
        public float quantity { get; set; }
        [Display(Name = "Price")]
        public float price { get; set; }
    }
}

View视图页面代码

@model MyShop.ViewModels.CreateDealVM

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Deals</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                @Html.LabelFor(model => model.selectedCustomer, htmlAttributes: new { @class = "control-label col-md-2" })

                <div class="col-md-10">
                    @Html.DropDownListFor(model => model.selectedCustomerId, Model.selectedCustomer,"--Select--" )                
                </div>
            </div>
            <div class="form-group">
                <label asp-for="deal.product" class="control-label"></label>
                <select asp-for="deal.product" class="form-control"></select>
                <span asp-validation-for="deal.product" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="deal.saleDate" class="control-label"></label>
                <input asp-for="deal.saleDate" class="form-control" />
                <span asp-validation-for="deal.saleDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="deal.quantity" class="control-label"></label>
                <input asp-for="deal.quantity" class="form-control" />
                <span asp-validation-for="deal.quantity" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="deal.price" class="control-label"></label>
                <input asp-for="deal.price" class="form-control" />
                <span asp-validation-for="deal.price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

我尝试过相关解决方案但未解决问题,寻求有效修复方案。


解决方案

问题根源

  1. Post方法中vm.deal可能为null:表单提交时模型绑定未正确实例化deal对象,导致访问vm.deal.customer触发空引用异常。
  2. ModelState无效时未重新填充下拉数据:验证失败直接返回View(),视图所需的selectedCustomer集合为空,渲染时触发空引用。
  3. Deals模型外键配置不规范:仅定义导航属性customer,未显式声明外键字段,EF Core无法正确处理关联关系。

修复步骤

1. 修正Deals模型,添加显式外键字段

namespace MyShop.Models
{
    [Table("Deals")]
    public class Deals
    {
        [Key]
        [Display(Name = "ID")]
        public int dealId { get; set; }

        // 添加显式外键字段
        [Display(Name = "Customer ID")]
        public int CustomerId { get; set; }

        [ForeignKey("CustomerId")]
        [Display(Name = "Customer")]
        public Customer customer { get; set; }

        [Display(Name = "CustomerName")]
        public string? parentCustomerName { get; set; }
        
        [Display(Name = "product")]
        public DealTypeEnum product { get; set; }
        [Display(Name = "Date")]
        public DateTime saleDate { get; set; }
        [Display(Name = "Quantity")]
        public float quantity { get; set; }
        [Display(Name = "Price")]
        public float price { get; set; }
    }
}

2. 改进Post方法,确保视图模型完整性

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateDealVM vm)
{
    // 初始化deal对象(防止模型绑定未创建)
    vm.deal ??= new Deals();

    if (ModelState.IsValid)
    {
        try
        {
            // 直接设置外键ID,无需加载整个Customer对象,提升性能
            vm.deal.CustomerId = vm.selectedCustomerId;
            _context.Deals.Add(vm.deal);
            _context.SaveChanges();
            return RedirectToAction("Index");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            ModelState.AddModelError("", $"创建交易失败:{e.Message}");
        }
    }

    // 验证失败时重新填充下拉列表
    vm.selectedCustomer = new SelectList(_context.Customers.ToList(), "customerId", "customerName");
    return View(vm);
}

3. 优化视图,确保表单绑定正确

  • 显式声明表单提交方法为post:
<form asp-action="Create" method="post">
  • 给下拉列表添加样式并确保绑定正确:
@Html.DropDownListFor(model => model.selectedCustomerId, Model.selectedCustomer, "--Select--", new { @class = "form-control" })

4. 可选:初始化ViewModel的deal属性

在CreateDealVM构造函数中初始化deal,避免null:

public class CreateDealVM
{
    public CreateDealVM()
    {
        deal = new Deals();
    }
    public Deals deal { get; set; }
    public IEnumerable<SelectListItem> selectedCustomer { get; set; }
    public int selectedCustomerId { get; set; }
}

内容的提问来源于stack exchange,提问作者Alloylo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:48:26