C# 序列化JSON.NET作业对象,同时过滤掉某些属性
我的代码中有一个大的任意JSON结构作为C# 序列化JSON.NET作业对象,同时过滤掉某些属性,c#,.net,json.net,C#,.net,Json.net,我的代码中有一个大的任意JSON结构作为JObject引用 我想序列化此结构,除非遇到一个JObject包含名为type且值为“加密的”的属性,然后我想在写入对象之前删除相邻的数据属性 换句话说,如果我遇到这种情况: { type: "encrypted", name: "some-name", data: "<base64-string>" } 我无法对结构进行变异,在变异之前克隆它效率太低,因此我尝试使用JsonConverter,如下所示: public clas
JObject
引用
我想序列化此结构,除非遇到一个JObject
包含名为type
且值为“加密的”
的属性,然后我想在写入对象之前删除相邻的数据
属性
换句话说,如果我遇到这种情况:
{
type: "encrypted",
name: "some-name",
data: "<base64-string>"
}
我无法对结构进行变异,在变异之前克隆它效率太低,因此我尝试使用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);
}
}
假设您使用的是Newtonsoft JSON.Net库 要有条件地序列化属性,请添加一个方法,该方法返回与属性同名的布尔值,然后在方法名称前面加上ShouldSerialize。方法的结果确定是否序列化属性。如果该方法返回true,则将序列化该属性,如果返回false,则将跳过该属性 例如:
public class EncryptedData
{
public string Type { get; set; }
public string Name { get; set; }
public string Data { get; set; }
public bool ShouldSerializeData()
{
// don't serialize the Data property if the Type equals "encrypted"
return (Type != "encrypted");
}
}
需要构建转换器来处理
JToken
,并且它必须递归工作,以确保所有加密数据都被编辑
我能够使以下转换器工作:
public class RemoveEncryptedDataConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(JToken).IsAssignableFrom(objectType);
}
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)
{
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);
}
}
}
然后您可以这样使用它,其中stream
是您的输出流,input
是您的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);
}
Fiddle:尝试
返回true
而不是返回objectType==typeof(JObject)
在你的CanConvert
方法中,告诉我它是否有效。同时尝试将此方法添加到你的转换器=>public override bool CanRead{get{return false;}}
谢谢@er shoaib,不幸的是,这不起作用,因为WriteJson
仍然只为结构的左节点调用。谢谢,这是一个有用的技巧,但是在这种情况下,JSON是任意结构,因此我无法将其反序列化为具体类型。谢谢Brian,这真的很有帮助!有趣的是,我的测试仍然失败,直到我从使用改为使用JsonConvert.SerializeObject(…)
。实际上,我需要写入流,但是WriteTo(…)
也会以与ToString(…)
相同的方式失败。我有点惊讶他们产生了不同的输出,但这复制了它:。你知道我如何在得到与JsonConvert.SerializeObject
相同的输出的同时写入流吗?@jamesthrley更新了我的答案以显示流的方法。
public class RemoveEncryptedDataConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(JToken).IsAssignableFrom(objectType);
}
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)
{
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);
}
}
}
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);
}
}
}
using (StreamWriter sw = new StreamWriter(stream)) // or StringWriter if you prefer
using (JsonWriter writer = new JsonTextWriter(sw))
{
writer.Formatting = Formatting.Indented;
input.RedactedWriteTo(writer);
}