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

添加JsonSerializer转换器后.NET 6中FromBody返回null的问题求助

问题与解决方案

问题现象

在.NET 6项目的Startup中添加自定义JsonSerializer转换器后,通过AJAX提交数据时,控制器方法中[FromBody]标记的参数始终为null;注释掉这些转换器后,代码可正常运行。

相关代码

Startup配置

services.AddControllersWithViews().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.Converters.Add(new DateTimeConverterFactory());
    options.JsonSerializerOptions.Converters.Add(new DecimalConverterFactory());
    options.JsonSerializerOptions.Converters.Add(new IntConverterFactory());
});

AJAX提交代码

function PerformAction(url, data) {
    var model = {};
    model.ListOfIds = data;

    var testModel = JSON.stringify(model);
    $.ajax({
        url: url,
        type: "POST",
        Traditional: true,
        data: testModel,
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        success: function (ValidationErrors) {
            // 业务逻辑处理
        }
    });
}

控制器代码

[HttpPost]
public IActionResult AjaxReject([FromBody] ListModel testModel)
{
    var listOfIds = testModel?.ListOfIds; // testModel始终为null
}

public class ListModel
{
    public List<int> ListOfIds { get; set; }
}

示例转换器代码(IntConverterFactory)

public class IntConverterFactory : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        return typeToConvert == typeof(int) ||
            typeToConvert == typeof(int?);
    }

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        if (typeToConvert == typeof(int))
        {
            return new IntConverter();
        }
        else if (typeToConvert == typeof(int?))
        {
            return new NullableIntConverter();
        }

        throw new NotSupportedException("当前转换器工厂不支持该类型");
    }
}

public class IntConverter : JsonConverter<int>
{
    public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var stringValue = reader.GetString();
        return IntExtensions.GetFormattedInt(stringValue);
    }

    public override void Write(
        Utf8JsonWriter writer,
        int objectToWrite,
        JsonSerializerOptions options)
    {
        writer.WriteNumberValue(objectToWrite);
    }
}

public class NullableIntConverter : JsonConverter<int?>
{
    public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.GetString() is { } value)
        {
            return IntExtensions.GetFormattedInt(value);
        }

        return null;
    }

    public override void Write(
        Utf8JsonWriter writer,
        int? objectToWrite,
        JsonSerializerOptions options)
    {
        if (objectToWrite is { })
            writer.WriteNumberValue((int)objectToWrite);
        else writer.WriteNullValue();
    }
}

问题原因

自定义转换器的Read方法存在逻辑缺陷:AJAX提交的JSON数据中,ListOfIds的元素是JSON数字类型(比如[1,2,3]),但转换器直接调用reader.GetString()获取值——只有当JSON Token类型为字符串时,GetString()才会返回有效值,数字类型调用该方法会返回null,进而导致转换失败。一旦单个属性转换失败,整个模型绑定就会终止,最终testModel为null。

Decimal转换器也存在同样问题,若遇到JSON数字类型的decimal值,GetString()无法获取有效值,导致转换出错。

解决方案

修改转换器的Read方法,增加对JSON数字类型的判断和处理,同时兼容字符串类型输入,确保两种格式都能正常转换。

修改后的IntConverter代码

public class IntConverter : JsonConverter<int>
{
    public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string stringValue;
        // 根据当前Token类型分支处理
        if (reader.TokenType == JsonTokenType.String)
        {
            stringValue = reader.GetString();
        }
        else if (reader.TokenType == JsonTokenType.Number)
        {
            // 若无需特殊格式处理,直接读取数值即可
            return reader.GetInt32();
            // 若需通过IntExtensions处理,可改为:
            // stringValue = reader.GetInt32().ToString();
        }
        else
        {
            throw new JsonException($"不支持的Token类型:{reader.TokenType}");
        }
        return IntExtensions.GetFormattedInt(stringValue);
    }

    public override void Write(
        Utf8JsonWriter writer,
        int objectToWrite,
        JsonSerializerOptions options)
    {
        writer.WriteNumberValue(objectToWrite);
    }
}

public class NullableIntConverter : JsonConverter<int?>
{
    public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }
        
        string stringValue;
        if (reader.TokenType == JsonTokenType.String)
        {
            stringValue = reader.GetString();
            if (string.IsNullOrWhiteSpace(stringValue))
            {
                return null;
            }
        }
        else if (reader.TokenType == JsonTokenType.Number)
        {
            return reader.GetInt32();
            // 若需通过IntExtensions处理,可改为:
            // stringValue = reader.GetInt32().ToString();
        }
        else
        {
            throw new JsonException($"不支持的Token类型:{reader.TokenType}");
        }
        return IntExtensions.GetFormattedInt(stringValue);
    }

    public override void Write(
        Utf8JsonWriter writer,
        int? objectToWrite,
        JsonSerializerOptions options)
    {
        if (objectToWrite is { })
            writer.WriteNumberValue((int)objectToWrite);
        else writer.WriteNullValue();
    }
}

修改后的DecimalConverter代码

public class DecimalConverter : JsonConverter<decimal>
{
    public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string decimalToParse;
        if (reader.TokenType == JsonTokenType.String)
        {
            decimalToParse = reader.GetString();
        }
        else if (reader.TokenType == JsonTokenType.Number)
        {
            // 若无需特殊格式处理,直接读取数值即可
            return reader.GetDecimal();
            // 若需通过DecimalExtensions处理,可改为:
            // decimalToParse = reader.GetDecimal().ToString();
        }
        else
        {
            throw new JsonException($"不支持的Token类型:{reader.TokenType}");
        }
        return DecimalExtensions.GetFormattedDecimal(decimalToParse);
    }

    public override void Write(
        Utf8JsonWriter writer,
        decimal objectToWrite,
        JsonSerializerOptions options)
    {
        writer.WriteNumberValue(objectToWrite);
    }
}

public class NullableDecimalConverter : JsonConverter<decimal?>
{
    public override decimal? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }
        
        string value;
        if (reader.TokenType == JsonTokenType.String)
        {
            value = reader.GetString();
            if (string.IsNullOrWhiteSpace(value))
            {
                return null;
            }
        }
        else if (reader.TokenType == JsonTokenType.Number)
        {
            return reader.GetDecimal();
            // 若需通过DecimalExtensions处理,可改为:
            // value = reader.GetDecimal().ToString();
        }
        else
        {
            throw new JsonException($"不支持的Token类型:{reader.TokenType}");
        }
        return DecimalExtensions.GetFormattedDecimal(value);
    }

    public override void Write(
        Utf8JsonWriter writer,
        decimal? objectToWrite,
        JsonSerializerOptions options)
    {
        if (objectToWrite is { })
            writer.WriteNumberValue(objectToWrite.Value);
        else writer.WriteNullValue();
    }
}

补充说明

  • 如果IntExtensions.GetFormattedInt和DecimalExtensions.GetFormattedDecimal方法需要处理特殊格式字符串(比如带千分位、货币符号的字符串),则保留将数字转换为字符串后传入的逻辑;如果只是普通数值转换,直接调用reader.GetInt32()/reader.GetDecimal()效率更高。
  • 建议在DateTimeConverterFactory中也做类似兼容处理,避免遇到相同问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 17:10:39