1

I need to have a dynamic property-name for the serialization.

public class Home
{
    public virtual int Id { get; set; } // value: 2

    public virtual string propertyName { get; set; } // value: administration

    public virtual string Text { get; set; } // value: text1
} 

should serialize to:

{
  "Id": 2,
  "administration": "text1"
}

Is there any way to serialize that? Which is the best way to deserialize it?

Mike
  • 850
  • 10
  • 33
Alex Seitz
  • 66
  • 2
  • 7

2 Answers2

4

According to this post on how to Dynamically rename or ignore properties without changing the serialized class by Rico Suter, you can add a class which extends DefaultContractResolver named PropertyRenameAndIgnoreSerializerContractResolver.

So the model would look like:

public class Home
{
    [JsonProperty("firstName")]
    public int Id { get; set; } // value: 2

    //public Dictionary<string,string> dictionary { get; set; }

    [JsonProperty("propertyName")]
    public string propertyName { get; set; } // value: administration

    [JsonIgnore]
    public string Text { get; set; } // value: text1
}

And serialization would look like this:

var home = new Home();

home.Id = 2;
home.propertyName = "text1";

var jsonResolver = new PropertyRenameAndIgnoreSerializerContractResolver();
jsonResolver.RenameProperty(typeof(Home), "propertyName", "administration");

var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = jsonResolver;

var json = JsonConvert.SerializeObject(home, serializerSettings);

Which give the desire output.

Add this class PropertyRenameAndIgnoreSerializerContractResolver.cs:

public class PropertyRenameAndIgnoreSerializerContractResolver : DefaultContractResolver
{
    private readonly Dictionary<Type, HashSet<string>> _ignores;
    private readonly Dictionary<Type, Dictionary<string, string>> _renames;

    public PropertyRenameAndIgnoreSerializerContractResolver()
    {
        _ignores = new Dictionary<Type, HashSet<string>>();
        _renames = new Dictionary<Type, Dictionary<string, string>>();
    }

    public void IgnoreProperty(Type type, params string[] jsonPropertyNames)
    {
        if (!_ignores.ContainsKey(type))
            _ignores[type] = new HashSet<string>();

        foreach (var prop in jsonPropertyNames)
            _ignores[type].Add(prop);
    }

    public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
    {
        if (!_renames.ContainsKey(type))
            _renames[type] = new Dictionary<string, string>();

        _renames[type][propertyName] = newJsonPropertyName;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        if (IsIgnored(property.DeclaringType, property.PropertyName))
            property.ShouldSerialize = i => false;

        if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
            property.PropertyName = newJsonPropertyName;

        return property;
    }

    private bool IsIgnored(Type type, string jsonPropertyName)
    {
        if (!_ignores.ContainsKey(type))
            return false;

        return _ignores[type].Contains(jsonPropertyName);
    }

    private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
    {
        Dictionary<string, string> renames;

        if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
        {
            newJsonPropertyName = null;
            return false;
        }

        return true;
    }
}
KyleMit
  • 30,350
  • 66
  • 462
  • 664
Jatin Parmar
  • 647
  • 4
  • 14
3

Add a ToJObject method that returns a JObject.

public JObject ToJObject()
{
    JObject jObject = new JObject()
    {
        { "Id", Id },
        { propertyName, Text }
    }

    return jObject;
}

Then for Deserializing i would probably create a factory method something like this:

public static Home CreateFromJObject(JObject obj)
{
    Home h = new Home();

    foreach (var a in obj)
    {
        if (a.Key == "ID")
        {
            h.Id = a.Value.Value<int>();
        }
        else
        {
            h.propertyName = a.Key;
            h.Text = a.Value.Value<string>();
        }
    }

    return h;
}

Ofcause if you have multiple other values in there i would either change it to a switch or make sure that only the needed JObject is passed in there.

Mike
  • 850
  • 10
  • 33