我的代码中有一个大的任意
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); }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。