Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Json.NET populate readonly fields in a class?

Tags:

.net

json.net

I haven't seen much information about Json.NET supporting deserializing objects with readonly fields. I do notice that the .NET DataContract and DataMember attributes allow for populating readonly fields during deserializtion, but Json.NET doesn't seem to support this, at least from the behavior I'm seeing.

like image 392
Mark LeMoine Avatar asked Nov 14 '10 19:11

Mark LeMoine


2 Answers

Not the most elegant solution, but you can extend the DefaultConstractResolver to do it:

public class ContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        property.Writable = CanSetMemberValue(member, true);
        return property;
    }

    public static bool CanSetMemberValue(MemberInfo member, bool nonPublic)
    {
        switch (member.MemberType)
        {
            case MemberTypes.Field:
                var fieldInfo = (FieldInfo)member;

                return nonPublic || fieldInfo.IsPublic;
            case MemberTypes.Property:
                var propertyInfo = (PropertyInfo)member;

                if (!propertyInfo.CanWrite)
                    return false;
                if (nonPublic)
                    return true;
                return (propertyInfo.GetSetMethod(nonPublic) != null);
            default:
                return false;
        }
    }
}

I have just remove one little check from the CanSetMemberValue method. Unfortunately it's neither virtual nor an instance method, so I had to override CreateProperty as well.

like image 109
asgerhallas Avatar answered Nov 21 '22 15:11

asgerhallas


This can be done now. Declare your properties using the JsonProperty attribute, and ensure that they have a protected set declared:

[JsonProperty("Name")] public string Name {get; protected set;}

This didn't work for me when using only a get, but works perfectly with the protected set.

like image 21
Terry Lewis Avatar answered Nov 21 '22 14:11

Terry Lewis