Serialize Property, But Do Not Deserialize Property in JSON.Net

Making a property deserialize but not serialize with json.net

There are actually several fairly simple approaches you can use to achieve the result you want.

Let's assume, for example, that you have your classes currently defined like this:

class Config
{
public Fizz ObsoleteSetting { get; set; }
public Bang ReplacementSetting { get; set; }
}

enum Fizz { Alpha, Beta, Gamma }

class Bang
{
public string Value { get; set; }
}

And you want to do this:

string json = @"{ ""ObsoleteSetting"" : ""Gamma"" }";

// deserialize
Config config = JsonConvert.DeserializeObject<Config>(json);

// migrate
config.ReplacementSetting =
new Bang { Value = config.ObsoleteSetting.ToString() };

// serialize
json = JsonConvert.SerializeObject(config);
Console.WriteLine(json);

To get this:

{"ReplacementSetting":{"Value":"Gamma"}}

Approach 1: Add a ShouldSerialize method

Json.NET has the ability to conditionally serialize properties by looking for corresponding ShouldSerialize methods in the class.

To use this feature, add a boolean ShouldSerializeBlah() method to your class where Blah is replaced with the name of the property that you do not want to serialize. Make the implementation of this method always return false.

class Config
{
public Fizz ObsoleteSetting { get; set; }

public Bang ReplacementSetting { get; set; }

public bool ShouldSerializeObsoleteSetting()
{
return false;
}
}

Note: if you like this approach but you don't want to muddy up the public interface of your class by introducing a ShouldSerialize method, you can use an IContractResolver to do the same thing programmatically. See Conditional Property Serialization in the documentation.

Approach 2: Manipulate the JSON with JObjects

Instead of using JsonConvert.SerializeObject to do the serialization, load the config object into a JObject, then simply remove the unwanted property from the JSON before writing it out. It's just a couple of extra lines of code.

JObject jo = JObject.FromObject(config);

// remove the "ObsoleteSetting" JProperty from its parent
jo["ObsoleteSetting"].Parent.Remove();

json = jo.ToString();

Approach 3: Clever (ab)use of attributes

  1. Apply a [JsonIgnore] attribute to the property that you do not want to be serialized.
  2. Add an alternate, private property setter to the class with the same type as the original property. Make the implementation of that property set the original property.
  3. Apply a [JsonProperty] attribute to the alternate setter, giving it the same JSON name as the original property.

Here is the revised Config class:

class Config
{
[JsonIgnore]
public Fizz ObsoleteSetting { get; set; }

[JsonProperty("ObsoleteSetting")]
private Fizz ObsoleteSettingAlternateSetter
{
// get is intentionally omitted here
set { ObsoleteSetting = value; }
}

public Bang ReplacementSetting { get; set; }
}

Serialize Property, but Do Not Deserialize Property in Json.Net

Simplest method would be to mark the real property as [JsonIgnore] and create a get-only proxy property:

    /// <summary>
/// Gets or sets the country code, and province or state code delimited by a vertical pipe: <c>US|MI</c>
/// </summary>
[JsonIgnore]
public string CountryProvinceState
{
get
{
return string.Format("{0}|{1}", this.CountryCode, this.ProvinceState);
}
set
{
if (!string.IsNullOrWhiteSpace(value) && value.Contains("|"))
{
string[] valueParts = value.Split('|');
if (valueParts.Length == 2)
{
this.CountryCode = valueParts[0];
this.ProvinceState = valueParts[1];
}
}
}
}

[JsonProperty("countryProvinceState")]
string ReadCountryProvinceState
{
get { return CountryProvinceState; }
}

The proxy property can be private if you desire.

Update

If you have to do this for lots of properties in lots of classes, it might be easier to create your own ContractResolver that checks for a custom attribute. If found, the attribute would signal that the property is get-only:

[System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = false)]
public class GetOnlyJsonPropertyAttribute : Attribute
{
}

public class GetOnlyContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property != null && property.Writable)
{
var attributes = property.AttributeProvider.GetAttributes(typeof(GetOnlyJsonPropertyAttribute), true);
if (attributes != null && attributes.Count > 0)
property.Writable = false;
}
return property;
}
}

Then use it like:

[JsonProperty("countryProvinceState")]
[GetOnlyJsonProperty]
public string CountryProvinceState { get; set; }

And then:

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

var address = JsonConvert.DeserializeObject<Address>(jsonString, settings);

Json.NET does not deserialize property with custom getter and immutable type

The culprit is this line in your ClassWithCustomProperty class:

    get => value = (value ?? new ImmutableValue(0));

Json.Net's default behavior is to reuse existing objects rather than replace them. So when it is time to deserialize the ImmutableValue on ClassWithCustomProperty, the serializer first checks whether there is an existing value. The accessor (above) finds that there isn't, so it creates one with value 0, which is returned to the serializer. The serializer then attempts to reuse this existing object, but since it is readonly, there is no way to set the value 42 on it. So the value remains zero.

There is an ObjectCreationHandling setting which can be used to change this behavior. If you set it to Replace, it will work the way you want. Try like this:

var settings = new JsonSerializerSettings 
{
ObjectCreationHandling = ObjectCreationHandling.Replace
};
var obj = JsonConvert.DeserializeObject<ClassWithCustomProperty>(json, settings);

Fiddle: https://dotnetfiddle.net/UVDMsL

Can I instruct Json.NET to deserialize, but not serialize, specific properties?

You should be able to just use the ShouldSerialize* methods as shown in the question. These only impact serialization, not deserialization.

Json.NET Deserialize Property Without Deserializing Parent Object Above It

I suggest two approaches that are very explicit and easy to follow for the next developer looking at the code.

Two classes

creating a intermediate dto class that is used for deserialisation and then creating the business logic object from that intermediate object.

var withAttributes = Deserialise<ListingDto>();

var flatObject = new Listing(withAttributes);

One class

You could provide accessors at the top level which dip into the subclasses.

public class Listing
{
public AttributesDto Attributes {get; set}

...

public string Url => Attributes.Url; // Maybe '?.Url'
}

How to deserialize a property on JSON from one type but serialize to another type with the same name?

Thanks to @Fildor for leading me in the right direction.
The answer was deceptively simple, add a type converter and decorate the new property with the converter.

public class Something {
[JsonConverter(typeof(FeeConverter))]
public Fee Fee { get; set;}
}

public class Fee {
public decimal? Amount { get; set; }
public int Type { get; set; }
}

public class FeeConverter : JsonConverter
{

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Float || reader.TokenType == JsonToken.Integer)
{
var property = JValue.Load(reader);
return new Fee() { Amount = property.Value<decimal>() };
}

return serializer.Deserialize(reader, objectType);
}

public override bool CanWrite => false;

public override bool CanConvert(Type objectType) => false;
}

How to ignore a property from serialization but keep in for deserialization using json.net in c#

Could you have a method for the 'set' of Content and process the data into the right place.

public class Foo
{
[JsonProperty("id")]
public int Id { get; set; }

[JsonProperty("contentType")]
public object ContentType { get; set; }

[JsonProperty("content")]
public object Content { get; set {
//do something here with `value` e.g.
RelationshipContent = value; //change as required
DomainContent = value; //change as required
}
}

[JsonIgnore]
public Relationship RelationshipContent { get; set; }

[JsonIgnore]
public Domains DomainContent { get; set; }

}


Related Topics



Leave a reply



Submit