微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 在过滤掉某些属性时序列化JSON.NET JObject

我的代码中有一个大的任意 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

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

相关推荐