Xamarin.Forms应用中DbGeography无法正常工作的问题排查
解决方案:修复DbGeography反序列化仅部分生效的问题
我看了你的问题,核心问题出在自定义的DbGeographyConverter没有处理JSON中的引用标识符($id/$ref),同时对null场景的处理也不够完善。因为你的API返回的JSON里包含$id标记(比如示例里的"$id": "6"),Newtonsoft.Json默认会启用引用处理,当后续记录引用同一个GeoLocation时,会用$ref代替完整结构,这时候你的转换器直接读取Geography节点就会失败,返回null。另外,你的类属性混用了DataMemberAttribute和Newtonsoft.Json的特性,也可能导致序列化逻辑冲突。
咱们一步步来修复:
1. 调整DbGeography类,统一使用Newtonsoft.Json特性
把DataMemberAttribute换成JsonProperty,确保和你用的Json.NET序列化器匹配:
public class DbGeography { [JsonProperty("Geography")] public DbGeographyWellKnownValue Geography { get; set; } /// <summary> /// Custom FromText method /// </summary> public static DbGeography FromText(string wellKnownText, int coordinateSystemId) { return new DbGeography() { Geography = new DbGeographyWellKnownValue() { WellKnownText = wellKnownText, CoordinateSystemId = coordinateSystemId, } }; } }
2. 修复DbGeographyConverter,处理引用和null场景
修改ReadJson方法,先处理JSON引用、null值,再处理正常的JObject结构:
public class DbGeographyConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(DbGeography); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // 处理null值 if (reader.TokenType == JsonToken.Null) return null; // 处理JSON引用($ref) if (reader.TokenType == JsonToken.StartObject) { var jObj = JObject.Load(reader); if (jObj.ContainsKey("$ref")) { var referenceId = jObj["$ref"].ToString(); return serializer.ReferenceResolver.ResolveReference(serializer, referenceId); } // 处理正常的GeoLocation结构 var geographyToken = jObj["Geography"]; if (geographyToken == null || geographyToken.Type == JTokenType.Null) return null; var wellKnownText = geographyToken["WellKnownText"]?.ToString(); var coordinateIdToken = geographyToken["CoordinateSystemId"]; if (string.IsNullOrEmpty(wellKnownText) || coordinateIdToken == null) return null; if (int.TryParse(coordinateIdToken.ToString(), out int coordinateId)) { return DbGeography.FromText(wellKnownText, coordinateId); } } // 所有异常场景返回null return null; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var dbGeography = value as DbGeography; // 处理null或空的情况 if (dbGeography == null || dbGeography.Geography == null) { serializer.Serialize(writer, null); return; } // 正常序列化 serializer.Serialize(writer, value); } }
3. 验证Location类的特性
确保Location类的属性特性正确,没有冲突:
public class Location { [JsonProperty("GeoLocation")] [JsonConverter(typeof(DbGeographyConverter))] public DbGeography GeoLocation { get; set; } // 其他属性... }
为什么这样改?
- 你的原始转换器没有处理JSON的引用机制:当API返回的多条记录共享同一个GeoLocation时,Json.NET会用
$ref指向之前的$id,这时候直接读取Geography节点会找不到值,导致返回null。修复后的代码会先解析引用,复用已序列化的对象。 - 统一使用Json.NET的特性:之前混用
DataMemberAttribute(属于DataContractSerializer)和JsonProperty,可能导致序列化逻辑冲突,改用JsonProperty确保和Json.NET兼容。 - 完善了null值和异常场景的处理:避免因为某个节点缺失或格式错误导致整个对象反序列化失败。
这个修改应该能解决你遇到的"仅1条记录正常,3条为null"的问题,因为现在转换器能正确处理引用和各种边缘情况了。
内容的提问来源于stack exchange,提问作者Dumber_Texan2
相关产品推荐
相关产品推荐

