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

.NET 7中Ajax传递null数组到控制器被解析为空数组的原因

.NET 7 MVC中jQuery Ajax传递null字符串数组绑定问题解决方法

问题原因

ASP.NET MVC默认模型绑定器对未提交的数组类型参数,会自动初始化为长度为0的空数组,而非null。这是绑定器的默认行为:对于引用类型数组,即使没有收到对应请求参数,也会实例化空数组而非保留null。


解决方案

方法1:使用可空数组+配置模型绑定空值处理

将控制器参数改为可空数组,并配置模型绑定器允许未提交参数返回null:

控制器代码:

[HttpPost] 
public ActionResult Process(int employeeId, string[]? yearsWorked, string reason, string authorizer)

Program.cs/Startup.cs配置:

builder.Services.AddControllersWithViews()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
        options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
    })
    .AddMvcOptions(options =>
    {
        // 配置未提交参数时返回null
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(_ => "值不能为空");
        options.NullValueHandling = NullValueHandling.Ignore;
    });

方法2:显式传递null并使用JSON格式请求

修改Ajax代码,显式设置yearsWorked: null,同时确保请求以JSON格式发送(默认jQuery会将对象转为表单格式,无法正确传递null):

Ajax代码:

$('#' + freezeBtnId).on('click', function () {        
    var url = '/Employee/Process';        
    var data = { 
        employeeId: $('#hdnId').val(), 
        yearsWorked: null, // 显式传递null
        reason: $('#txtReason').val(), 
        authorizer: $('#txtAuthorizer').val()
    };

    $.ajax({
        url: url,
        type: 'POST',
        cache: false,
        async: true,
        contentType: "application/json", // 指定JSON内容类型
        data: JSON.stringify(data), // 序列化为JSON字符串
        success: function (data) {
            alert('success');
        }
    });
});

此方法下,控制器参数可保持string[] yearsWorked,JSON格式的null会被模型绑定器正确解析为null数组。

方法3:自定义模型绑定器

创建自定义绑定器,处理数组类型参数,当请求中无该参数时返回null:

自定义绑定器代码:

public class NullableArrayModelBinder<T> : IModelBinder where T : class
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (valueProviderResult == ValueProviderResult.None)
        {
            // 无对应参数时返回null
            bindingContext.Result = ModelBindingResult.Success(null);
            return Task.CompletedTask;
        }

        // 有参数时使用默认绑定逻辑
        var defaultBinder = new SimpleTypeModelBinder(typeof(T[]));
        return defaultBinder.BindModelAsync(bindingContext);
    }
}

控制器参数应用绑定器:

[HttpPost] 
public ActionResult Process(int employeeId, [ModelBinder(typeof(NullableArrayModelBinder<string>))] string[] yearsWorked, string reason, string authorizer)

也可以全局注册该绑定器,避免每个参数手动标注:

builder.Services.AddControllersWithViews()
    .AddMvcOptions(options =>
    {
        options.ModelBinderProviders.Insert(0, new BinderTypeModelBinderProvider(typeof(NullableArrayModelBinder<>)));
    });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 18:05:23