custom serializer for just one property in Json.NET

Json序列化的时候跳过加密字段

字段类定义如下
  public class Field
    {
        public bool IsEncrypted { get; set; }

        public string Name { get; set; }

        public Object Value { get; set; }
    }

需要序列化User类

public class User
    {
        public Field UserName { get; set; }

        public Field Password { get; set; }
    }

序列化的结果,加密字段密码也被序列化出来了

[Test]
        public void TestChuck()
        {
            User user = new User();
            Field field = new Field();
            field.IsEncrypted = false;
            field.Name = "UserName";
            field.Value = "chucklu";
            user.UserName = field;

            field = new Field();
            field.IsEncrypted = true;
            field.Name = "Password";
            field.Value = "123456";
            user.Password = field;

            string str = JsonConvert.SerializeObject(user);
            Console.WriteLine(str);
        }

{
"UserName": {
"IsEncrypted": false,
"Name": "UserName",
"Value": "chucklu"
},
"Password": {
"IsEncrypted": true,
"Name": "Password",
"Value": "123456"
}
}

  

 https://stackoverflow.com/questions/18521970/custom-serializer-for-just-one-property-in-json-net 

You can add a custom serializer to a single attribute like this:

public class Comment
{
    public string Author { get; set; }

    [JsonConverter(typeof(NiceDateConverter))]
    public DateTime Date { get; set; }

    public string Text { get; set; }
}

public class NiceDateConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var date = value as DateTime;
        var niceLookingDate = date.ToString("MMMM dd, yyyy 'at' H:mm tt");
        writer.WriteValue(niceLookingDate);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime);
    }
}

Then, when you serialize your object with JsonConvert.SerializeObject(), the custom serializer will be used for the Date property.

解决方案

继承JsonConverter实现自定义的Converter,FieldConverter,然后在属性上添加[JsonConverter(typeof(FieldConverter))]

 public class User
    {
        public Field UserName { get; set; }

        [JsonConverter(typeof(FieldConverter))]
        public Field Password { get; set; }
    }

    public class Field
    {
        public bool IsEncrypted { get; set; }

        public string Name { get; set; }

        public object Value { get; set; }
    }
  public class FieldConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value is Field field && !field.IsEncrypted)
            {
                var str = JsonConvert.SerializeObject(value);
                writer.WriteValue(str);
            }
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Field);
        }
    }

输出结果是

{
"UserName": {
"IsEncrypted": false,
"Name": "UserName",
"Value": "chucklu"
},
"Password": null
}

 类似的,如果Field 这样使用List<Field>

 public class User
    {
        public List<Field> list = new List<Field>();
    }

    public class Field
    {
        public bool IsEncrypted { get; set; }

        public string Name { get; set; }

        public object Value { get; set; }
    }
  [Test]
        public void TestChuck()
        {
            User user = new User();
            Field field = new Field();
            field.IsEncrypted = false;
            field.Name = "UserName";
            field.Value = "chucklu";
            user.list.Add(field);

            field = new Field();
            field.IsEncrypted = true;
            field.Name = "Password";
            field.Value = "123456";
            user.list.Add(field);

            string str = JsonConvert.SerializeObject(user);
            Console.WriteLine(str);
        }

输出是

{
"list": [
{
"IsEncrypted": false,
"Name": "UserName",
"Value": "chucklu"
},
{
"IsEncrypted": true,
"Name": "Password",
"Value": "123456"
}
]
}

 方案

唯一的问题是,把转义的双引号打出来了   使用 writer.WriteRawValue(str);可以避免json字符串被内部转义

  public class FieldConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value is List<Field> list)
            {
                var temp = list.Where(x => !x.IsEncrypted).ToList();
                var str = JsonConvert.SerializeObject(temp);
                writer.WriteValue(str);
  writer.WriteRawValue(str); } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } public override bool CanConvert(Type objectType) { return objectType == typeof(List<Field>); } }

 {"list":"[{"IsEncrypted":false,"Name":"UserName","Value":"chucklu"}]"}   本来[]两边是没有双引号的,里面的转义也是多出来的

{"List":[{"IsEncrypted":false,"Name":"UserName","Value":"chucklu"}]} 必须是 writer.WriteRawValue(str);

如果是 writer.WriteRaw(str);的话,结果中会多出一个null

原文地址:https://www.cnblogs.com/chucklu/p/11050226.html