使用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反序列化问题的通用方法
以后遇到类似问题,按这个流程排查:
先看原始响应内容
在反序列化前,把stringData打印出来(或者用断点查看),确认API返回的JSON结构到底是什么样的——这是最关键的一步,90%的问题都是结构不匹配导致的。逐层级对比类与JSON结构
把JSON格式化后(用VS自带的JSON格式化功能就行),和你的C#类逐层级对比:- 检查是否有嵌套层级错误(比如你漏了
matchings这一层) - 检查字段名是否完全一致(即使开了大小写不敏感,也要注意拼写,比如JSON是
matchings不能写成matching)
- 检查是否有嵌套层级错误(比如你漏了
用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");检查属性的可访问性
System.Text.Json默认只处理公共可读写属性,如果你用的是公共字段(比如你原来的public string code;),需要在JsonSerializerOptions里设置IncludeFields = true才会被处理,不过更推荐用自动属性{ get; set; }。
备注:内容来源于stack exchange,提问作者Alexander Farber

