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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:22:58