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

ASP.NET Core MVC表单数组JSON反序列化失败问题求助

问题原因

后端LocationServiceEditDto中的LocationServicePrices是ICollection<LocationServicePriceDto>集合类型,但前端提交的JSON里,该字段是一个键为"0.PricePerUnit"这类字符串的对象,而非数组结构。JSON对象无法直接反序列化为集合类型,因此触发反序列化错误。

解决步骤

1. 修正视图的集合渲染逻辑(改用for循环)

ASP.NET Core模型绑定对集合的识别依赖索引化的name属性,foreach循环无法自动生成符合规范的绑定结构,建议改用for循环(需先将ICollection转为List):

@{
    var tierList = Model.LocationServicePrices.ToList();
}
@for (int i = 0; i < tierList.Count; i++)
{
    <div class="form-group">
        <label>@tierList[i].PricingTierName</label>
        <!-- 隐藏域传递层级ID,后端需该字段识别对应层级 -->
        <input type="hidden" asp-for="@tierList[i].PricingTierId" />
        <!-- 隐藏域传递关联ID(更新现有数据时需要) -->
        <input type="hidden" asp-for="@tierList[i].LocationServiceId" />
        <!-- 价格输入框,由asp-for自动生成正确的name属性 -->
        <input class="form-control" type="text" asp-for="@tierList[i].PricePerUnit" 
               data-rule-number="true" data-rule-min="0" data-rule-max="@AppConsts.MaxDecimalDatabaseLength">
    </div>
}

这里移除了手动指定的name,让asp-for自动生成LocationServicePrices[i].PricePerUnit这类符合模型绑定规范的属性名,同时补充必要的隐藏字段,确保后端能获取完整的LocationServicePriceDto数据。

2. 调整前端序列化逻辑,生成正确的数组结构

如果原serializeFormToObject方法无法解析索引式name,可手动处理表单数据,将其转换为数组结构:

this.save = function() {
    if (!_$form.valid()) {
        _$form.showValidateMessage();
        return;
    }

    // 手动解析表单数据为正确的对象结构
    var formData = _$form.serializeArray();
    var servicePrice = {};
    var locationServicePrices = [];

    formData.forEach(function(item) {
        var nameParts = item.name.split('.');
        // 处理集合类型字段
        if (nameParts[0] === 'LocationServicePrices') {
            var index = parseInt(nameParts[1].replace(/\[|\]/g, ''));
            var fieldName = nameParts[2];
            
            if (!locationServicePrices[index]) {
                locationServicePrices[index] = {};
            }
            locationServicePrices[index][fieldName] = item.value;
        } else {
            // 处理普通字段
            servicePrice[item.name] = item.value;
        }
    });

    servicePrice.LocationServicePrices = locationServicePrices;
    console.log(servicePrice);

    _modalManager.setBusy(true);
    _serviceService.editLocationService(servicePrice).done(function() {
        abp.notify.info('Saved successfully.');
        _modalManager.close();
        abp.event.trigger('app.createOrEditServicePriceModalSaved');
    }).always(function() {
        _modalManager.setBusy(false);
    });
};

调整后生成的JSON结构会变为:

{
    "Id": "",
    "ServiceId": "2031",
    "LocationId": "2",
    "MaterialUomId": "6",
    "Cost": "123",
    "LocationServicePrices": [
        {"PricingTierId": "xxx", "LocationServiceId": "xxx", "PricePerUnit": "1"},
        {"PricingTierId": "xxx", "LocationServiceId": "xxx", "PricePerUnit": "2"},
        ...
    ] 
}

3. 确保后端Dto字段匹配

验证LocationServicePriceDto包含前端传递的所有字段,避免反序列化时丢失数据:

public class LocationServicePriceDto
{
    public int? LocationServiceId { get; set; }
    public int PricingTierId { get; set; }
    public decimal PricePerUnit { get; set; }
    // 其他业务所需字段...
}

额外说明

  • 若使用ABP框架,若自带的serializeFormToObject仍无法正确解析,直接替换为上述手动处理逻辑即可。
  • 后端控制器代码无需修改,只要前端传递的JSON结构正确,ASP.NET Core模型绑定会自动将数组反序列化为ICollection<LocationServicePriceDto>。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 04:45:05