将 JSON 数组反序列化为 List<T> C# 时出错

Posted

技术标签:

【中文标题】将 JSON 数组反序列化为 List<T> C# 时出错【英文标题】:Error Deserializing JSON Array to List<T> C# 【发布时间】:2021-10-11 12:04:13 【问题描述】:

我正在尝试反序列化 JSON 数组,我有一个节点接收发布请求并生成 C# 子进程,JSON 数组通过 tmp 文件传入。当我尝试反序列化 JSON 数组时,它会抛出此错误:

Error: Command failed: dotnet OptiTools.dll "/tmp/tmp-1-FtT45M2y3swD"
Unhandled exception. Newtonsoft.Json.JsonSerializationException: Error converting value "[  "lat" : 38.904896, "lng" : -99.340191, "name" : "1"  ,  "lat" : 38.911362, "lng" : -99.354436, "name" : "2" ,  "lat" : 38.895442, "lng" : -99.318193, "name" : "3" ,  "lat" : 38.889632, "lng" : -99.318160, "name" : "4" ,  "lat" : 38.885637, "lng" : -99.320847, "name" : "5" ,  "lat" : 38.885635, "lng" : -99.321922, "name" : "6" ,  "lat" : 38.885781, "lng" : -99.333766, "name" : "7" ,  "lat" : 38.887466, "lng" : -99.339046, "name" : "8" ,  "lat" : 38.885649, "lng" : -99.336521, "name" : "9" ,  "lat" : 38.886740, "lng" : -99.352277, "name" : "10" ,  "lat" : 38.885956, "lng" : -99.324307, "name" : "11" ,  "lat" : 38.886353, "lng" : -99.323947, "name" : "12" ,  "lat" : 38.889276, "lng" : -99.319662, "name" : "13" ,  "lat" : 38.889065, "lng" : -99.319364, "name" : "14" ,  "lat" : 38.887511, "lng" : -99.319004, "name" : "15" ,  "lat" : 38.887947, "lng" : -99.320324, "name" : "16" ,  "lat" : 38.880091, "lng" : -99.317064, "name" : "17" ,  "lat" : 38.880365, "lng" : -99.317002, "name" : "18" ,  "lat" : 38.880087, "lng" : -99.315899, "name" : "19" ,  "lat" : 38.878123, "lng" : -99.314144, "name" : "20" ,  "lat" : 38.878123, "lng" : -99.315373, "name" : "21" ,  "lat" : 38.879612, "lng" : -99.315917, "name" : "22" ,  "lat" : 38.879633, "lng" : -99.317538, "name" : "23" ,  "lat" : 38.879511, "lng" : -99.318917, "name" : "24" ,  "lat" : 38.872725, "lng" : -99.317589, "name" : "25" ,  "lat" : 38.871773, "lng" : -99.316660, "name" : "26" ,  "lat" : 38.875437, "lng" : -99.317690, "name" : "27" ,  "lat" : 38.878437, "lng" : -99.317671, "name" : "28" ,  "lat" : 38.884577, "lng" : -99.317633, "name" : "29" ,  "lat" : 38.892398, "lng" : -99.321025, "name" : "31" ,  "lat" : 38.892897, "lng" : -99.324546, "name" : "32" ,  "lat" : 38.889882, "lng" : -99.333179, "name" : "33" ,  "lat" : 38.891063, "lng" : -99.333657, "name" : "34" ,  "lat" : 38.891065, "lng" : -99.333364, "name" : "35" ,  "lat" : 38.890792, "lng" : -99.333155, "name" : "36" ,  "lat" : 38.885620, "lng" : -99.334919, "name" : "37" ,  "lat" : 38.893812, "lng" : -99.336019, "name" : "38" ,  "lat" : 38.895593, "lng" : -99.332730, "name" : "39" ,  "lat" : 38.898277, "lng" : -99.335429, "name" : "40" ,  "lat" : 38.897998, "lng" : -99.331866, "name" : "41" ,  "lat" : 38.897998, "lng" : -99.333338, "name" : "42" ,  "lat" : 38.898068, "lng" : -99.332990, "name" : "43" ,  "lat" : 38.893207, "lng" : -99.328365, "name" : "44" ,  "lat" : 38.894332, "lng" : -99.333072, "name" : "45" ,  "lat" : 38.896496, "lng" : -99.331118, "name" : "46" ,  "lat" : 38.894145, "lng" : -99.327817, "name" : "47" ,  "lat" : 38.893864, "lng" : -99.327712, "name" : "48" ,  "lat" : 38.892924, "lng" : -99.327338, "name" : "49" ,  "lat" : 38.886863, "lng" : -99.327525, "name" : "50" ,  "lat" : 38.885832, "lng" : -99.325107, "name" : "51" ,  "lat" : 38.888653, "lng" : -99.326059, "name" : "52" ,  "lat" : 38.891872, "lng" : -99.324385, "name" : "53" ,  "lat" : 38.891696, "lng" : -99.323332, "name" : "54" ,  "lat" : 38.895412, "lng" : -99.320524, "name" : "55" ,  "lat" : 38.895387, "lng" : -99.323585, "name" : "56" ,  "lat" : 38.896950, "lng" : -99.326502, "name" : "57" ,  "lat" : 38.896957, "lng" : -99.323612, "name" : "58" ,  "lat" : 38.896700, "lng" : -99.320395, "name" : "59" ,  "lat" : 38.894557, "lng" : -99.320348, "name" : "60" ,  "lat" : 38.893441, "lng" : -99.323515, "name" : "61" ,  "lat" : 38.893441, "lng" : -99.323637, "name" : "62" ,  "lat" : 38.897367, "lng" : -99.327636, "name" : "63" ,  "lat" : 38.899215, "lng" : -99.327631, "name" : "64" ,  "lat" : 38.894731, "lng" : -99.331423, "name" : "65" ,  "lat" : 38.892939, "lng" : -99.330233, "name" : "66" ,  "lat" : 38.892921, "lng" : -99.330233, "name" : "67" ,  "lat" : 38.889079, "lng" : -99.330286, "name" : "68" ,  "lat" : 38.888606, "lng" : -99.330295, "name" : "69" ,  "lat" : 38.888508, "lng" : -99.331809, "name" : "70" ,  "lat" : 38.888655, "lng" : -99.329502, "name" : "71" ,  "lat" : 38.886589, "lng" : -99.317605, "name" : "72" ,  "lat" : 38.886589, "lng" : -99.317605, "name" : "73" ,  "lat" : 38.887620, "lng" : -99.317617, "name" : "74" ,  "lat" : 38.894740, "lng" : -99.317583, "name" : "75" ,  "lat" : 38.895597, "lng" : -99.317589, "name" : "76" ,  "lat" : 38.903833, "lng" : -99.317629, "name" : "77" ,  "lat" : 38.903859, "lng" : -99.317628, "name" : "78" ,  "lat" : 38.907180, "lng" : -99.319754, "name" : "79" ,  "lat" : 38.902268, "lng" : -99.317992, "name" : "80" ,  "lat" : 38.901969, "lng" : -99.317995, "name" : "82" ,  "lat" : 38.901969, "lng" : -99.317995, "name" : "83" ,  "lat" : 38.901969, "lng" : -99.317995, "name" : "84" ,  "lat" : 38.900166, "lng" : -99.306594, "name" : "86" ,  "lat" : 38.899893, "lng" : -99.313189, "name" : "87" ,  "lat" : 38.899877, "lng" : -99.315322, "name" : "88" ,  "lat" : 38.907873, "lng" : -99.315153, "name" : "89" ,  "lat" : 38.901351, "lng" : -99.321161, "name" : "90" ,  "lat" : 38.889548, "lng" : -99.317579, "name" : "91"  ] " to type 'System.Collections.Generic.List`1[OptiTools.Locations]'. Path '', line 1, position 5805.
 ---> System.ArgumentException: Could not cast or convert from System.String to System.Collections.Generic.List`1[OptiTools.Locations].
   at Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType)
   at Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
   at OptiTools.JsonConverter.ExtractLoc(String jsonIn) in C:\Users\ryanb\Documents\Projects\Reoptimization\OptiTools\OptiTools\OptiTools\JsonConverter.cs:line 14
   at OptiTools.Program.Main(String[] args) in C:\Users\ryanb\Documents\Projects\Reoptimization\OptiTools\OptiTools\OptiTools\Program.cs:line 14
Aborted

    at ChildProcess.exithandler (child_process.js:275:12)
    at emitTwo (events.js:126:13)
    at ChildProcess.emit (events.js:214:7)
    at maybeClose (internal/child_process.js:925:16)
    at Socket.stream.socket.on (internal/child_process.js:346:11)
    at emitOne (events.js:116:13)
    at Socket.emit (events.js:211:7)
    at Pipe._handle.close [as _onclose] (net.js:567:12)

在我看来,JSON 数组的格式正确,可以反序列化为此位置列表,但由于某种原因无法转换。 Locations 对象很简单,应该不是问题

using System;
using System.Collections.Generic;
using System.Text;

namespace OptiTools

    public class Locations
    
        public double lat  get; set; 
        public double lng  get; set; 
        public string name  get; set; 
    

这也是我为转换 JSON 所做的类的代码:

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Text;
using Newtonsoft.Json.Linq;

namespace OptiTools

    public static class JsonConverter
    
        public static List<Locations> ExtractLoc(string jsonIn)
        
            List<Locations> locs = JsonConvert.DeserializeObject<List<Locations>>(jsonIn);
            return locs;
        
    

编辑:nodeJS 代码:

// javascript source code
//const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const tmp = require('tmp');
const fs = require('fs');
const app = express();
const router = express.Router();

const hostname = '0.0.0.0';
const port = 3000;

const cpro = require('child_process');
const file = 'OptiTools.dll';

var outp = "";



app.use(cors());
app.use(bodyParser.urlencoded( extended: false ));
app.use(bodyParser.json());

app.post('/', (req, res) => 
    console.log(JSON.stringify(req.body.data));
    tmp.file(function createTmp(err, path, fd, cleanupCallback) 
        if (err) throw err;

        fs.writeFile(path, [JSON.stringify(req.body.data)], (err) => 
            if (err)  throw err  else 
                console.log(path)
                var runner = cpro.exec(`dotnet $file "$path"`,  cwd: "../OptiTools/OptiTools/bin/Release/netcoreapp3.1" , (error, out, err) => 
                    if (error) 
                        throw error;
                     else 
                        outp = out;
                        res.statusCode = 200;
                        res.setHeader('Access-Control-Allow-Origin', '*');
                        res.setHeader('Content-Type', 'application/json');
                        res.send(outp);
                        cleanupCallback();
                    
                );
            
        );
    );
);

app.listen(port, hostname, () => 
    console.log(`Server running at http://$hostname:$port/`);
);

节点将此记录为 JSON:

"[  \"lat\" : 38.904896, \"lng\" : -99.340191, \"name\" : \"1\"  ,  \"lat\" : 38.911362, \"lng\" : -99.354436, \"name\" : \"2\" ,  \"lat\" : 38.895442, \"lng\" : -99.318193, \"name\" : \"3\" ,  \"lat\" : 38.889632, \"lng\" : -99.318160, \"name\" : \"4\" ,  \"lat\" : 38.885637, \"lng\" : -99.320847, \"name\" : \"5\" ,  \"lat\" : 38.885635, \"lng\" : -99.321922, \"name\" : \"6\" ,  \"lat\" : 38.885781, \"lng\" : -99.333766, \"name\" : \"7\" ,  \"lat\" : 38.887466, \"lng\" : -99.339046, \"name\" : \"8\" ,  \"lat\" : 38.885649, \"lng\" : -99.336521, \"name\" : \"9\" ,  \"lat\" : 38.886740, \"lng\" : -99.352277, \"name\" : \"10\" ,  \"lat\" : 38.885956, \"lng\" : -99.324307, \"name\" : \"11\" ,  \"lat\" : 38.886353, \"lng\" : -99.323947, \"name\" : \"12\" ,  \"lat\" : 38.889276, \"lng\" : -99.319662, \"name\" : \"13\" ,  \"lat\" : 38.889065, \"lng\" : -99.319364, \"name\" : \"14\" ,  \"lat\" : 38.887511, \"lng\" : -99.319004, \"name\" : \"15\" ,  \"lat\" : 38.887947, \"lng\" : -99.320324, \"name\" : \"16\" ,  \"lat\" : 38.880091, \"lng\" : -99.317064, \"name\" : \"17\" ,  \"lat\" : 38.880365, \"lng\" : -99.317002, \"name\" : \"18\" ,  \"lat\" : 38.880087, \"lng\" : -99.315899, \"name\" : \"19\" ,  \"lat\" : 38.878123, \"lng\" : -99.314144, \"name\" : \"20\" ,  \"lat\" : 38.878123, \"lng\" : -99.315373, \"name\" : \"21\" ,  \"lat\" : 38.879612, \"lng\" : -99.315917, \"name\" : \"22\" ,  \"lat\" : 38.879633, \"lng\" : -99.317538, \"name\" : \"23\" ,  \"lat\" : 38.879511, \"lng\" : -99.318917, \"name\" : \"24\" ,  \"lat\" : 38.872725, \"lng\" : -99.317589, \"name\" : \"25\"  ] "

【问题讨论】:

您在此处拥有的 JSON(偷偷地嵌入在错误消息中而不是在问题中发布)可以完美地转换为您在此处显示的类。还有一些你没有向我们展示的东西。 这是为了让问题变得有意义。最好将代码(和 JSON)减少到最低限度。您是否需要 5000 个字符的 JSON 来证明它不起作用?只需创建一个minimal reproducible example 我的猜测是您的 JSON 字符串是错误的并且是双重编码的。检查原始字符串,它是否被"...."包围?但是,如果您不向我们展示 ACTUAL JSON,那么我们将无能为力。 错误Could not cast or convert from System.String to System.Collections.Generic.List``1[OptiTools.Locations]表明DavidG是对的。 看起来你在调用 JSON.stringify 的字符串已经是 JSON。 【参考方案1】:

您在 NodeJS 应用程序中对 JSON 进行双重编码。这意味着在 C# 代码中,JSON 是一个简单的字符串,因此理论上您可以在那里对其进行两次解码:

var decodedJson = JsonConvert.DeserializeObject<string>(jsonIn);
List<Locations> locs = JsonConvert.DeserializeObject<List<Locations>>(decodedJson);

当然,那将是相当愚蠢和浪费资源的。相反,您应该修复 NodeJS 应用程序,使其不会通过删除 JSON.stringify 来进行双重编码。

【讨论】:

以上是关于将 JSON 数组反序列化为 List<T> C# 时出错的主要内容,如果未能解决你的问题,请参考以下文章

JSON反序列化是否为IEnumerable 产生结果?

将 JSON 反序列化为 List<List<KeyValuePair>> 结果为空

将 JSON 对象反序列化为 List<type> 不适用于 asmx 服务

使用 Json.NET 将异构 JSON 数组反序列化为协变 List<>

使用Jackson将JSON数组反序列化为单个Java对象

是否可以将 XML 反序列化为 List<T>?