使用NewtonSoft.Json修改属性名称的序列化方式

时间:2017-04-28 11:44:54

标签: c# json json.net

我在我的应用程序中使用NewtonSoft.Json将许多类型的对象序列化为字符串并将它们发送到第三方服务。现在,其中一些服务对Json格式有限制,例如它们不支持JSON属性名称中的点:

{
   "PropertyOne":{
      "SubProperty.One":"SubValue.One" <- invalid!
   },
   "Property.Two":"ValueTwo"  <- invalid!
}

如何修改NewtonSoft.Json序列化对象的方式,以便用例如下划线替换属性名称中的所有点:

{
   "PropertyOne":{
      "SubProperty_One":"SubValue.One"
   },
   "Property_Two":"ValueTwo"
}

注意:我无法用DataAnnotations属性实现这一点,因为我序列化的一些对象在第三方库中,我无法修改它们。

3 个答案:

答案 0 :(得分:1)

您可以使用自定义ContractResolver轻松完成此操作:

class ReplaceDotsWithUnderscoresResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);
        prop.PropertyName = prop.PropertyName.Replace('.', '_');
        return prop;
    }
}

像这样使用:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    ContractResolver = new ReplaceDotsWithUnderscoresResolver(),
    Formatting = Formatting.Indented
};

string json = JsonConvert.SerializeObject(your_object, settings);

工作演示:https://dotnetfiddle.net/hQOJdh

答案 1 :(得分:0)

您可以使用AutoMapper并将第三方类型映射到您自己的类型。然后,您就可以将JsonPropertyAttribute应用于需要自定义名称的属性。

另一种方法可能是用正则表达式替换生成的JSON:

var json = @"{
    ""PropertyOne"":{
        ""SubProperty.One"":""SubValue.One""
 },
    ""Property.Two.Three"":""ValueTwo""
 }";

string result;

while (true)
{
    result = Regex.Replace(json, @"(""[^.]+)(\.)(.+"":)", "$1_$3", RegexOptions.IgnoreCase);
    if (json == result)
    {
        break;
    }
    json = result;
}

Console.WriteLine(result);

哪个会以您想要的方式输出结果:

{
    "PropertyOne":{
        "SubProperty_One":"SubValue.One"
},
    "Property_Two_Three":"ValueTwo"
}

答案 2 :(得分:0)

实现所需目标的方法之一是尽早拦截序列化/反序列化过程,方法是重写JsonReader和JsonWriter。

public class CustomSerializer : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
            throw new ArgumentNullException("value");

        var properties = value.GetType().GetProperties();
        writer.WriteStartObject();
        foreach (var property in properties)
        {
            string propertyName = property.Name.Replace('.', '_');
            // just write new property name and value
            writer.WritePropertyName(propertyName);
            writer.WriteValue(property.GetValue(value, new object[] { }));

        }

        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jsonObject = JObject.Load(reader);
        List<JProperty> properties = jsonObject.Properties().ToList();

        object instance = Activator.CreateInstance(objectType);

        PropertyInfo[] objectProperties = objectType.GetProperties();
        foreach (var objectProperty in objectProperties)
        {
            JProperty jsonProperty = properties.SingleOrDefault(prop => prop.Name == objectProperty.Name.Replace('_', '.'));
            if (jsonProperty != null)
            {
                objectProperty.SetValue(instance, jsonProperty.Value.ToString(), new object[] { });
            }
        }

        return instance;
    }

    public override bool CanConvert(Type objectType)
    {
        return true; // your logic here
    }
}

和用法:

JsonConvert.SerializeObject(your_object, new CustomSerializer());