Private setters in Json.Net

Starting from C# 9 it's recommended to use Init Only Setters rather than private setters when initialising an object from JSON. E.g. public string Summary { get; init; }

If you insist on private setters, then you'd need to annotate such properties with JsonInclude attribute.

Either way, JsonSerializer.DeserializeAsync will deserialise the properties.


@Daniel's answer (Alt2) is spot on, but I needed this to work for both private setters and getters (I'm working with an API that actually has a few write-only things, like user.password.) Here's what I ended up with:

public class NonPublicPropertiesResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
        var prop = base.CreateProperty(member, memberSerialization);
        if (member is PropertyInfo pi) {
            prop.Readable = (pi.GetMethod != null);
            prop.Writable = (pi.SetMethod != null);
        }
        return prop;
    }
}

Registered thusly:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
    ContractResolver = new NonPublicPropertiesResolver()
};

Updated, new answer

I've written a source distribution NuGet for this, that installs a single file with two custom contract resolvers:

  • PrivateSetterContractResolver
  • PrivateSetterCamelCasePropertyNamesContractResolver

Install the NuGet package:

Install-Package JsonNet.ContractResolvers

Then just use any of the resolvers:

var settings = new JsonSerializerSettings
{
    ContractResolver = new PrivateSetterContractResolver()
};

var model = JsonConvert.DeserializeObject<Model>(json, settings);

You can read about it here: http://danielwertheim.se/json-net-private-setters-nuget/

GitHub repo: https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers

Old answer (still valid)

There are two alternatives that can solve the problem.

Alt 1: On the deserializers

ContractResolver.DefaultMembersSearchFlags =
                             DefaultMembersSearchFlags | BindingFlags.NonPublic;

The default serialization option supports all types of class member. Therefore this solution will return all private members types including fields. I'm only interested in also supporting private setters.

Alt2: Create a custom ContractResolver:

Therefore this is the better options since we just check the properties.

public class SisoJsonDefaultContractResolver : DefaultContractResolver 
{
    protected override JsonProperty CreateProperty(
        MemberInfo member,
        MemberSerialization memberSerialization)
    {
        //TODO: Maybe cache
        var prop = base.CreateProperty(member, memberSerialization);

        if (!prop.Writable)
        {
            var property = member as PropertyInfo;
            if (property != null)
            {
                var hasPrivateSetter = property.GetSetMethod(true) != null;
                prop.Writable = hasPrivateSetter;
            }
        }

        return prop;
    }
}

For more information, read my post: http://danielwertheim.se/json-net-private-setters/


I came here looking for the actual attribute that makes Json.NET populate a readonly property when deserializing, and that's simply [JsonProperty], e.g.:

[JsonProperty]
public Guid? ClientId { get; private set; }

Alternative Solution

Just provide a constructor that has a parameter matching your property:

public class Foo
{
    public string Bar { get; }

    public Foo(string bar)
    {
        Bar = bar;
    }
}

Now this works:

string json = "{ \"bar\": \"Stack Overflow\" }";

var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow

I prefer this approach where possible since:

  • It doesn't require you to decorate your properties with attributes.
  • It works with both { get; private set; } and just { get; }.

Tags:

C#

Json.Net