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

使用System.Text.Json反序列化OSRM地图匹配服务响应时返回空对象(属性为null)的问题排查及调试方法咨询

使用System.Text.Json反序列化OSRM地图匹配服务响应时返回空对象(属性为null)的问题排查及调试方法咨询

我来帮你拆解这个问题,先讲核心原因,再给解决方案,最后分享这类JSON反序列化问题的通用调试思路。

核心问题:类结构与OSRM实际响应层级不匹配

你遇到的空对象问题,本质是你定义的C#类结构和OSRM Match API返回的JSON结构完全对不上。

OSRM Match接口的响应顶层结构里,legs并不是直接挂在根对象下的,而是嵌套在matchings数组的每一项中。你直接在OsrmResponse里声明legs属性,反序列化时自然找不到对应字段,导致属性为null——哪怕开了大小写不敏感也没用,因为层级错了。

举个OSRM响应的简化版结构:

{
  "code": "Ok",
  "matchings": [
    {
      "legs": [
        {
          "annotation": {
            "nodes": [12345, 67890]
          }
        }
      ]
    }
  ]
}

解决方案:调整类结构匹配响应层级

下面是适配OSRM响应的修正代码,同时优化了属性定义(用自动属性替代字段,更符合C#规范):

namespace OsrmMapMatch
{
    public class OsrmResponse
    {
        public string Code { get; set; }
        public List<OsrmMatching> Matchings { get; set; }
    }

    public class OsrmMatching
    {
        public List<OsrmLeg> Legs { get; set; }
    }

    public class OsrmLeg
    {
        public OsrmAnnotation Annotation { get; set; }
    }

    public class OsrmAnnotation
    {
        public List<uint> Nodes { get; set; }
    }

    internal class Program
    {
        static async Task Main(string[] args)
        {
            const string HttpClientMapMatch = "HttpClientMapMatch";
            const string OsrmUri = "10.757938,52.437444;10.764379,52.437314;10.770562,52.439067;10.773268,52.436633?overview=simplified&radiuses=50;50;50;50&generate_hints=false&skip_waypoints=true&gaps=ignore&annotations=nodes&geometries=geojson";

            var serviceProvider = new ServiceCollection()
                .AddHttpClient(HttpClientMapMatch, httpClient =>
                {
                    httpClient.BaseAddress = new Uri("https://router.project-osrm.org/match/v1/driving/");
                }).BuildServiceProvider();

            var httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
            var httpClient = httpClientFactory.CreateClient(HttpClientMapMatch);

            var response = await httpClient.GetAsync(OsrmUri);
            if (response.IsSuccessStatusCode)
            {
                var stringData = await response.Content.ReadAsStringAsync();
                var options = new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true, // 适配OSRM的小写字段名
                    WriteIndented = true // 序列化时格式化输出,方便调试
                };
                var osrmResponse = JsonSerializer.Deserialize<OsrmResponse>(stringData, options);

                // 提取你需要的所有OSM节点
                var allNodes = osrmResponse?.Matchings?
                    .SelectMany(matching => matching.Legs)
                    .SelectMany(leg => leg.Annotation?.Nodes)
                    .ToList();

                Console.WriteLine($"提取到的OSM节点总数:{allNodes?.Count ?? 0}");
                Console.WriteLine("\n完整反序列化结果:");
                Console.WriteLine(JsonSerializer.Serialize(osrmResponse, options));
            }
        }
    }
}

调试这类JSON反序列化问题的通用方法

以后遇到类似问题,按这个流程排查:

  1. 先看原始响应内容
    在反序列化前,把stringData打印出来(或者用断点查看),确认API返回的JSON结构到底是什么样的——这是最关键的一步,90%的问题都是结构不匹配导致的。

  2. 逐层级对比类与JSON结构
    把JSON格式化后(用VS自带的JSON格式化功能就行),和你的C#类逐层级对比:

    • 检查是否有嵌套层级错误(比如你漏了matchings这一层)
    • 检查字段名是否完全一致(即使开了大小写不敏感,也要注意拼写,比如JSON是matchings不能写成matching)
  3. 用JsonDocument手动遍历验证
    如果不确定字段路径,可以用JsonDocument手动访问JSON节点,确认字段是否存在:

    using var doc = JsonDocument.Parse(stringData);
    var root = doc.RootElement;
    // 手动访问节点,确认路径是否正确
    var nodes = root.GetProperty("matchings")[0].GetProperty("legs")[0].GetProperty("annotation").GetProperty("nodes");
    
  4. 检查属性的可访问性
    System.Text.Json默认只处理公共可读写属性,如果你用的是公共字段(比如你原来的public string code;),需要在JsonSerializerOptions里设置IncludeFields = true才会被处理,不过更推荐用自动属性{ get; set; }。

备注:内容来源于stack exchange,提问作者Alexander Farber

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 11:24:31