.netframework升级为.net8以后元组数据返回格式变成了 [{}]

问题代码

问题描述:MatExpireMoney这个方法前端请求以后得到的返回值是[{}]

csharp 复制代码
public async Task<JsonResult> MatExpireMoney(int platId = 0)
 {
     if (platId == 0)
     {
         platId = NowUser.PlatId;
     }
     var schIds = GetSchIds(platId);
     var expireMatMoney = storageRepo.Where(r => (r.Qty1 > 0 || r.Qty2 > 0) && schIds.Contains(r.SchoolId) && r.ExpirDate < nowDate).Sum(r => (decimal?)(r.Price * (r.Qty1 + r.Qty2))) ?? 0;
     var value = PriceConvert(expireMatMoney);
     return Json(value);
 }
public List<(decimal Money, string Unit)> PriceConvert(decimal? price)
{
    var unit = "";
    if (price > 0)
    {
        if (price > 100000000)
        {
            price = (decimal?)Math.Round((double)(price / 100000000), 2);
            unit = "亿";
        }
        else if (price > 10000)
        {
            price = (decimal?)Math.Round((double)(price / 10000), 2);
            unit = "万";
        }
        else
        {
            price = price;
            unit = "元";
        }

    }
    else
    {
        price = 0;
        unit = "元";
    }
    List<(decimal Money, string Unit)> model = new List<(decimal Money, string Unit)>();
    model.Add(((decimal)price, unit));
    return model;
} 

原因

从 .NET Framework 升级到 .NET 8 后,返回的数据格式变成了 [{}],这通常是因为 .NET Core 及更高版本(包括 .NET 8)对 JSON 序列化的默认行为发生了变化

  1. 默认序列化器变化

    在 .NET Framework 中,默认使用的是 Newtonsoft.Json(即 Json.NET)进行 JSON 序列化。

    在 .NET Core 及更高版本中,默认使用的是 System.Text.Json,它的行为与 Newtonsoft.Json 有所不同。

  2. System.Text.Json 的行为差异

    System.Text.Json 对匿名类型、值类型和集合的序列化行为与 Newtonsoft.Json 不同。

    例如,System.Text.Json 会将 List<(decimal Money, string Unit)> 序列化为 [{}],因为它无法直接处理元组类型的集合。

  3. 返回类型问题

    在 .NET Framework 中,JsonResult 可能对返回值进行了隐式处理,而在 .NET 8 中,JsonResult 的行为更加严格。

解决方案

方案 1:修改返回类型

将 List<(decimal Money, string Unit)> 改为一个明确的类类型,System.Text.Json 可以更好地处理类类型的序列化。

csharp 复制代码
public class MoneyModel
{
    public decimal Money { get; set; }
    public string Unit { get; set; }
}

public List<MoneyModel> PriceConvert(decimal? price)
{
    var unit = "";
    if (price > 0)
    {
        if (price > 100000000)
        {
            price = (decimal?)Math.Round((double)(price / 100000000), 2);
            unit = "亿";
        }
        else if (price > 10000)
        {
            price = (decimal?)Math.Round((double)(price / 10000), 2);
            unit = "万";
        }
        else
        {
            price = price;
            unit = "元";
        }
    }
    else
    {
        price = 0;
        unit = "元";
    }

    return new List<MoneyModel>
    {
        new MoneyModel { Money = (decimal)price, Unit = unit }
    };
}

然后在 MatExpireMoney 方法中直接返回 List:

csharp 复制代码
public async Task<JsonResult> MatExpireMoney(int platId = 0)
{
    if (platId == 0)
    {
        platId = NowUser.PlatId;
    }
    if (platId == 155) // 航空学院 特殊处理
    {
        var path = "/135/screen/new/timeout/r.do";
        var hk_Value = await HK_GetRequest<List<HK_MoneyModel>>(platId, path, "食材过期金额");
        return Json(hk_Value);
    }

    var schIds = GetSchIds(platId);
    var expireMatMoney = storageRepo
        .Where(r => (r.Qty1 > 0 || r.Qty2 > 0) && schIds.Contains(r.SchoolId) && r.ExpirDate < nowDate)
        .Sum(r => (decimal?)(r.Price * (r.Qty1 + r.Qty2))) ?? 0;

    var value = PriceConvert(expireMatMoney);
    return Json(value);
}

方案 2:配置 System.Text.Json 的序列化选项

如果不想修改返回类型,可以通过配置 System.Text.Json 的序列化选项来支持元组类型的序列化。

在 Startup.cs 或 Program.cs 中配置 JSON 选项:

csharp 复制代码
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = null; // 保持属性名称大小写
        options.JsonSerializerOptions.Converters.Add(new TupleConverter()); // 添加自定义元组转换器
    });

然后实现一个自定义的 JsonConverter 来处理元组类型:

csharp 复制代码
public class TupleConverter : JsonConverter<List<(decimal Money, string Unit)>>
{
    public override List<(decimal Money, string Unit)> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, List<(decimal Money, string Unit)> value, JsonSerializerOptions options)
    {
        writer.WriteStartArray();
        foreach (var item in value)
        {
            writer.WriteStartObject();
            writer.WriteNumber("Money", item.Money);
            writer.WriteString("Unit", item.Unit);
            writer.WriteEndObject();
        }
        writer.WriteEndArray();
    }
}

方案3:方案 3:回退到 Newtonsoft.Json

如果不想修改代码逻辑,可以回退到 Newtonsoft.Json,这是 .NET Framework 中默认的 JSON 序列化库。

安装 Microsoft.AspNetCore.Mvc.NewtonsoftJson 包:

csharp 复制代码
dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson

在 Startup.cs 或 Program.cs 中配置:

csharp 复制代码
builder.Services.AddControllers()
    .AddNewtonsoftJson(); // 使用 Newtonsoft.Json 作为默认序列化器

总结

推荐方案 1:修改返回类型为明确的类类型,这是最规范和可维护的方式。

方案 2:适合需要保留元组类型的场景,但需要额外实现自定义转换器。

方案 3:适合快速迁移,但长期来看不建议依赖 Newtonsoft.Json。

相关推荐
wybshyy4 小时前
WebApi使用 (.Net Framework版)
数据库·.net
时光追逐者5 小时前
分享2款 .NET 开源且强大的翻译工具
c#·.net·wpf·微软技术·翻译工具
林晓lx6 小时前
开箱即用的.NET MAUI组件库 V-Control 发布了!
c#·.net·maui
hhw1991126 小时前
.net的一些知识点
开发语言·.net
喵叔哟6 小时前
3. 【.NET Aspire 从入门到实战】--理论入门与环境搭建--环境搭建
java·开发语言·.net
李游Leo9 小时前
mac 安装 dotnet 环境
安全·macos·.net
来恩10039 小时前
C# 使用ADO.NET访问数据全解析
开发语言·c#·.net
专注VB编程开发20年15 小时前
C#项目引用VB.NET 类库项目,生成一个EXE,这是什么原理
windows·microsoft·.net
杨晓风-linda17 小时前
《VB.net之沉淀》
.net