如何反序列化带额外分页属性的NTS FeatureCollection?
问题描述
调用第三方API返回的GeoJSON FeatureCollection 包含游标分页所需的额外属性(如links、numberReturned、timeStamp),但NetTopologySuite(NTS)自带的FeatureCollection类没有这些属性。使用GeoJsonConverterFactory可以正常反序列化地理特征部分,但尝试单独反序列化分页属性到自定义POCO时,属性值均为null,无法获取分页信息。
提供的代码示例中,两次反序列化分别处理FeatureCollection和FeatureCollectionResponse,但分页属性未被正确解析。
解决方案
方法一:自定义包装类复用NTS序列化逻辑
创建包含额外分页属性的包装类,内嵌FeatureCollection,利用NTS转换器处理地理数据,同时保留分页属性。
步骤1:定义包装类
public class Link { public string Rel { get; set; } public string Type { get; set; } public string Title { get; set; } public string Href { get; set; } } public class PaginatedFeatureCollection { // 额外分页属性 public DateTime TimeStamp { get; set; } public Link[] Links { get; set; } public int NumberReturned { get; set; } // NTS核心FeatureCollection,对应GeoJSON的features数组 public FeatureCollection Features { get; set; } }
步骤2:反序列化配置与调用
var serializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); serializerOptions.Converters.Add(new GeoJsonConverterFactory()); var paginatedResult = JsonSerializer.Deserialize<PaginatedFeatureCollection>(json, serializerOptions); // 访问地理特征 Console.WriteLine($"第一个特征ID: {paginatedResult.Features[0].Id}"); // 访问分页信息 Console.WriteLine($"返回数量: {paginatedResult.NumberReturned}"); Console.WriteLine($"下一页链接: {paginatedResult.Links.First(l => l.Rel == "next")?.Href}");
方法二:自定义JsonConverter扩展FeatureCollection
编写自定义转换器,先提取分页属性,再委托NTS转换器处理核心FeatureCollection,将额外属性存入FeatureCollection的ExtendedProperties字典。
步骤1:编写自定义转换器
public class FeatureCollectionWithPaginationConverter : JsonConverter<FeatureCollection> { private readonly GeoJsonConverterFactory _ntsConverterFactory = new(); public override FeatureCollection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 读取完整JSON文档以提取额外属性 using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; // 解析分页属性 var timeStamp = root.GetProperty("timeStamp").GetDateTime(); var links = JsonSerializer.Deserialize<Link[]>(root.GetProperty("links").GetRawText(), options); var numberReturned = root.GetProperty("numberReturned").GetInt32(); // 委托NTS转换器反序列化核心FeatureCollection var featureCollection = JsonSerializer.Deserialize<FeatureCollection>(root.GetRawText(), options); // 将额外属性存入ExtendedProperties featureCollection.ExtendedProperties["timeStamp"] = timeStamp; featureCollection.ExtendedProperties["links"] = links; featureCollection.ExtendedProperties["numberReturned"] = numberReturned; return featureCollection; } public override void Write(Utf8JsonWriter writer, FeatureCollection value, JsonSerializerOptions options) { // 序列化时复用NTS逻辑,可按需扩展 _ntsConverterFactory.GetConverter(typeof(FeatureCollection)).Write(writer, value, options); } }
步骤2:使用自定义转换器
var serializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); // 替换默认NTS转换器为自定义转换器 serializerOptions.Converters.Add(new FeatureCollectionWithPaginationConverter()); var featureCollection = JsonSerializer.Deserialize<FeatureCollection>(json, serializerOptions); // 从ExtendedProperties获取分页信息 var numberReturned = (int)featureCollection.ExtendedProperties["numberReturned"]; var links = (Link[])featureCollection.ExtendedProperties["links"]; Console.WriteLine($"返回数量: {numberReturned}"); Console.WriteLine($"下一页链接: {links.First(l => l.Rel == "next")?.Href}");
原代码问题说明
你之前两次反序列化失败的核心原因:
- 第二次反序列化未传入包含NTS转换器的
serializerOptions,且默认配置未开启驼峰命名匹配(JSON中是links,类属性是Links); - 重复反序列化同一JSON字符串效率较低,且容易出现流读取问题。
如果要保留两次反序列化的方式,需给第二次反序列化传入相同配置:
var paginationInformation = JsonSerializer.Deserialize<FeatureCollectionResponse>(json, serializerOptions);
但仍推荐使用前两种更高效的方案。
内容的提问来源于stack exchange,提问作者David H
相关产品推荐
相关产品推荐

