如何在.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
相关产品推荐
相关产品推荐

