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

如何在.NET中实现自定义JsonConverter处理Firestore对象的序列化与反序列化

自定义JsonConverter适配Firestore REST API请求体

针对你的Channel类以及嵌套的User/Message类,我来分享一个适配Firestore REST API格式的自定义JsonConverter实现思路。Firestore的REST API要求请求体使用特定的字段值结构(比如字符串对应stringValue、数字对应integerValue、数组对应arrayValue、对象对应mapValue),所以我们需要在序列化时把常规的C#对象转成这种格式。

第一步:明确Firestore REST的核心序列化规则

先理清楚基础映射逻辑:

  • 基础类型(string/long):包装成{ "类型Value": 值 }的结构
  • 嵌套对象(User/Message):包装成{ "mapValue": { "fields": 序列化后的对象字段 } }
  • 集合类型(IEnumerable/IEnumerable):包装成{ "arrayValue": { "values": [ 每个元素的序列化结果 ] } }

第二步:实现自定义JsonConverter

下面是完整的代码实现,包含通用的对象处理逻辑,方便后续扩展其他嵌套类:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;

public class ChannelFirestoreConverter : JsonConverter<Channel>
{
    public override void WriteJson(JsonWriter writer, Channel value, JsonSerializer serializer)
    {
        var firestoreRoot = new JObject();
        var fieldsContainer = new JObject();

        // 逐个处理Channel的属性
        fieldsContainer.Add("Name", CreateFirestoreValue(value.Name));
        fieldsContainer.Add("OwnerId", CreateFirestoreValue(value.OwnerId));
        fieldsContainer.Add("Messages", CreateFirestoreArrayValue(value.Messages));
        fieldsContainer.Add("Users", CreateFirestoreArrayValue(value.Users));

        firestoreRoot.Add("fields", fieldsContainer);
        firestoreRoot.WriteTo(writer);
    }

    // 反序列化方法(如果不需要从Firestore响应转成Channel,可直接抛异常)
    public override Channel ReadJson(JsonReader reader, Type objectType, Channel existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("Deserialization is not required for this request body use case");
    }

    // 通用方法:生成单个值的Firestore格式
    private JToken CreateFirestoreValue(object value)
    {
        if (value == null)
        {
            return new JObject { ["nullValue"] = "" };
        }

        var typeCode = Type.GetTypeCode(value.GetType());
        switch (typeCode)
        {
            case TypeCode.String:
                return new JObject { ["stringValue"] = (string)value };
            case TypeCode.Int64:
                return new JObject { ["integerValue"] = (long)value };
            // 可扩展其他类型:bool→booleanValue、double→doubleValue等
            default:
                // 处理嵌套对象(User/Message这类)
                return CreateFirestoreMapValue(value);
        }
    }

    // 生成嵌套对象的Firestore map结构
    private JToken CreateFirestoreMapValue(object obj)
    {
        var fields = new JObject();
        // 遍历对象的所有公开实例属性
        foreach (PropertyInfo prop in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            var propValue = prop.GetValue(obj);
            fields.Add(prop.Name, CreateFirestoreValue(propValue));
        }
        return new JObject { ["mapValue"] = new JObject { ["fields"] = fields } };
    }

    // 生成集合的Firestore array结构
    private JToken CreateFirestoreArrayValue(IEnumerable<object> collection)
    {
        var valuesArray = new JArray();
        foreach (var item in collection ?? Enumerable.Empty<object>())
        {
            valuesArray.Add(CreateFirestoreValue(item));
        }
        return new JObject { ["arrayValue"] = new JObject { ["values"] = valuesArray } };
    }
}

第三步:使用转换器序列化Channel对象

当你需要把Channel实例转成Firestore请求体时,只需要在序列化时指定这个转换器即可:

var testChannel = new Channel
{
    Name = "Gaming Lounge",
    OwnerId = 1001,
    Messages = new List<Message> { new Message { SenderUserId = 1002 } },
    Users = new List<User> { new User { UserId = "user_1001", Pseudonym = "ShadowKnight" } }
};

var serializerSettings = new JsonSerializerSettings
{
    Converters = new List<JsonConverter> { new ChannelFirestoreConverter() }
};

string firestoreRequestBody = JsonConvert.SerializeObject(testChannel, serializerSettings);

这段代码会生成完全符合Firestore REST API要求的请求体格式,你可以直接把这个JSON字符串作为请求体发送到Firestore的创建/更新接口。

额外提示

  • 如果需要支持更多基础类型(比如布尔值、浮点数),可以在CreateFirestoreValue的switch分支中添加对应的处理逻辑
  • 你的类属性都是公开getter,反射可以正常读取值;如果后续调整属性访问权限,需要修改CreateFirestoreMapValue中的BindingFlags参数
  • 若不需要反序列化功能,ReadJson方法保持抛出异常的状态即可,不会影响请求体的序列化

内容的提问来源于stack exchange,提问作者user3574857

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:24:33