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

.NET Core Web App AJAX调用控制器Action抛出System.ArgumentNullException

问题分析与解决方案

你的代码出现ArgumentNullException以及移除日期ID后模型为null的问题,主要源于日期序列化/解析错误、模型绑定失败和缺少输入验证这几个关键点,下面逐一分析并给出修复方案:


核心问题拆解

  1. 无效日期导致模型绑定失败
    当new Date($("#milestoneDate").val())解析输入的日期字符串失败时,会生成一个Invalid Date对象,JSON序列化后会变成null或者.NET Core无法识别的格式。而你的Milestone模型中Date是非空的DateTime类型,这直接触发模型绑定失败,抛出ArgumentNullException。
    另外,模型里的DisplayFormat属性有语法错误:"{0:d" 少了闭合的大括号,应该改为"{0:d}"。

  2. 输入验证缺失
    点击添加按钮前,没有检查milestoneText是否为空,也没有验证日期格式是否合法,导致无效数据直接被发送到后端。

  3. 移除日期ID后的模型空值问题
    移除日期输入框的ID后,$("#milestoneDate").val()获取不到值,date变量变为undefined,序列化后请求中缺少Date字段,同样因为模型的Date是非空类型,模型绑定完全失败,最终milestone参数为null。


分步修复方案

1. 修正模型的DisplayFormat属性

先把模型里的语法错误改掉:

namespace TIB.Models
{
    public class Milestone
    {
        [Key] 
        public int Id { get; set; }
        [DisplayName("")]
        [StringLength(30, ErrorMessage ="Milestone cannot exceed 30 characters.")]  
        public string MilestoneName { get; set; }
        [DisplayName("Milestone Date")]
        [DisplayFormat(DataFormatString = "{0:d}")] // 修复闭合大括号
        public DateTime Date { get; set; }
        [ForeignKey("ProjectId")]
        public int ProjectId { get; set; }     
    }   
}

2. 前端添加严格的输入验证与日期处理

使用moment.js(你代码里已经用到了)来严格验证日期格式,避免无效日期被发送:

$("#addMilestoneBtn").on('click', function (e) {
    e.preventDefault();
    $('#loading-overlay').fadeIn();

    // 获取并清洗输入值
    const milestoneText = $("#milestoneText").val().trim();
    const dateStr = $("#milestoneDate").val().trim();
    const projectId = $("#projectId").val();

    // 验证里程碑文本不为空
    if (!milestoneText) {
        $("#milestoneValidation").show();
        $('#loading-overlay').fadeOut();
        return false;
    }
    $("#milestoneValidation").hide();

    // 用moment严格验证日期格式(匹配你设置的'l'格式)
    const date = moment(dateStr, 'L', true);
    if (!date.isValid()) {
        alert("请输入有效的日期格式");
        $('#loading-overlay').fadeOut();
        return false;
    }

    // 转换为ISO格式字符串,确保.NET能正确解析
    const milestoneDetails = {
        Id: 0,
        MilestoneName: milestoneText,
        ProjectId: Number(projectId),
        Date: date.toISOString()
    };

    const jsonData = JSON.stringify(milestoneDetails);

    $.ajax({
        type: "POST",
        url: '/TIB/Forms/MilestoneAddorUpdate',
        data: jsonData,
        contentType: "application/json",
        dataType: "json",
        success: OnSuccess,
        error: OnErrorCall
    });

    function OnSuccess(response) {
        if (response) {             
            updateFormTables('milestoneTable');
            const today = moment().format('l');
            $("#milestoneDate").val(today);
            $("#milestoneText").val("");
            $('#loading-overlay').fadeOut();
        }        
    }

    function OnErrorCall(response) {
        alert("Error. Milestone not added. " + response.responseText);
        $('#loading-overlay').fadeOut();
    }

    return false;
});

3. 后端增强模型验证与错误处理

把控制器Action的返回类型改为IActionResult,这样可以返回更明确的HTTP错误状态码,同时添加模型验证:

[HttpPost("~/Forms/MilestoneAddorUpdate")]
public IActionResult MilestoneAddorUpdate([FromBody] Milestone milestone)
{
    // 检查模型是否绑定成功、是否合法
    if (milestone == null || !ModelState.IsValid)
    {
        return BadRequest("无效的请求数据,请检查输入");
    }

    using (SqlConnection sqlConnection = new SqlConnection(_configuration.GetConnectionString("TIBDB")))
    {
        sqlConnection.Open();
        using (SqlCommand sqlCmd = new SqlCommand("usp_MilestoneAddorEdit", sqlConnection))
        {
            sqlCmd.CommandType = CommandType.StoredProcedure;
            sqlCmd.Parameters.AddWithValue("Id", milestone.Id);
            sqlCmd.Parameters.AddWithValue("ProjectId", milestone.ProjectId);
            sqlCmd.Parameters.AddWithValue("Date", milestone.Date);
            sqlCmd.Parameters.AddWithValue("MilestoneName", milestone.MilestoneName);

            sqlCmd.ExecuteNonQuery();
        }
    }

    // 返回Ok结果,携带布尔值
    return Ok(true);
}

4. 可选:允许日期为空(如果业务允许)

如果你的业务场景支持里程碑日期为空,可以把模型的Date属性改为可空类型:

public DateTime? Date { get; set; }

这样即使日期解析失败,模型绑定也不会完全失败,你可以在后端判断并处理空值情况。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 16:57:20