加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读