c# – 在过滤掉某些属性时序列化JSON.NET JObject
发布时间:2020-12-15 22:54:16 所属栏目:百科 来源:网络整理
导读:我的代码中有一个大的任意 JSON结构作为JObject引用. 我想序列化这个结构,除非我遇到一个包含一个名为type的属性的JObject,其值为“encrypted”,然后我想在写入对象之前删除相邻的data属性. 换句话说,如果我遇到这个: { type: "encrypted",name: "some-name
我的代码中有一个大的任意
JSON结构作为JObject引用.
我想序列化这个结构,除非我遇到一个包含一个名为type的属性的JObject,其值为“encrypted”,然后我想在写入对象之前删除相邻的data属性. 换句话说,如果我遇到这个: { type: "encrypted",name: "some-name",data: "<base64-string>" } 它将被序列化为: { type: "encrypted",name: "some-name" } 我不能改变结构,在变异之前克隆它会效率太低,所以我尝试使用JsonConverter如下: public class RemoveEncryptedDataSerializer : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(JObject); } public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer) { throw new NotImplementedException(); } public override void WriteJson(JsonWriter writer,object value,JsonSerializer serializer) { var o = (JObject)value; if (o.Value<string>("type") != "encrypted") { o.WriteTo(writer); return; } var copy = o.DeepClone(); copy["data"]?.Parent.Remove(); copy.WriteTo(writer); } } 但是,CanConvert函数似乎只是使用不是从JToken派生的类型调用,所以我的WriteJson函数永远不会被调用. 还有另一种方法来实现这一目标吗? 编辑:以下是一些可用于测试的代码: [TestMethod] public void ItShouldExcludeEncryptedData() { var input = JObject.Parse(@" { a: { type: 'encrypted',name: 'some-name',data: 'some-data' } }"); var expected = JObject.Parse(@" { a: { type: 'encrypted',} }"); var output = input.ToString(Formatting.Indented,new RemoveEncryptedDataSerializer()); Assert.AreEqual( expected.ToString(Formatting.Indented),output); } 解决方法
需要构建转换器来处理JToken,它必须递归工作以确保编辑所有加密数据.
我能够使用以下转换器: public class RemoveEncryptedDataConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(JToken).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader,JsonSerializer serializer) { JToken token = (JToken)value; if (token.Type == JTokenType.Object) { bool omitDataProperty = token.Value<string>("type") == "encrypted"; writer.WriteStartObject(); foreach (var prop in token.Children<JProperty>()) { if (omitDataProperty && prop.Name == "data") continue; writer.WritePropertyName(prop.Name); serializer.Serialize(writer,prop.Value); // recurse } writer.WriteEndObject(); } else if (token.Type == JTokenType.Array) { writer.WriteStartArray(); foreach (var item in token.Children()) { serializer.Serialize(writer,item); // recurse } writer.WriteEndArray(); } else // JValue { token.WriteTo(writer); } } } 工作演示:https://dotnetfiddle.net/0K61Bz 如果要直接通过流使用JsonWriter,可以将转换器中的逻辑重构为递归扩展方法并使用它.如果您不使用序列化程序,则不需要转换器. public static class JsonExtensions { public static void RedactedWriteTo(this JToken token,JsonWriter writer) { if (token.Type == JTokenType.Object) { bool omitDataProperty = token.Value<string>("type") == "encrypted"; writer.WriteStartObject(); foreach (var prop in token.Children<JProperty>()) { if (omitDataProperty && prop.Name == "data") continue; writer.WritePropertyName(prop.Name); prop.Value.RedactedWriteTo(writer); // recurse } writer.WriteEndObject(); } else if (token.Type == JTokenType.Array) { writer.WriteStartArray(); foreach (var item in token.Children()) { item.RedactedWriteTo(writer); // recurse } writer.WriteEndArray(); } else // JValue { token.WriteTo(writer); } } } 然后你就可以像这样使用它,其中stream是你的输出流,输入是你的JObject: using (StreamWriter sw = new StreamWriter(stream)) // or StringWriter if you prefer using (JsonWriter writer = new JsonTextWriter(sw)) { writer.Formatting = Formatting.Indented; input.RedactedWriteTo(writer); } 小提琴:https://dotnetfiddle.net/l949HU (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- ruby-on-rails – 帮助程序中的HAML过滤器
- ruby-on-rails – 由于以前的错误,Redis EXECABORT事务被丢
- AJAX中的请求方式以及同步异步的区别
- ruby-on-rails – 在Rails 3.1中,这种情况下连接表会调用什
- U-Boot的常用命令详解
- vb.net 教程 3-4 窗体编程 公共控件7 DateTimePicker &
- C#序列化与反序列化(Serialize,Deserialize)实例详解
- c# – 单元测试中的Mock IHttpContextAccessor
- cocos2d-x lua与c++简单交互
- solr配置文件solrconfig.xml解析