While I've found plenty of approaches to deserializing specific properties while preventing them from serializing, I'm looking for the opposite behavior.
I've found plenty of questions asking the inverse:
Making a property deserialize but not serialize with json.net
Can I instruct Json.NET to deserialize, but not serialize, specific properties?
JSON.Net - Use JsonIgnoreAttribute only on serialization (But not when deserialzing)
How can I serialize a specific property, but prevent it from deserializing back to the POCO? Is there an attribute I can use to decorate the specific property?
Basically I'm looking for an equivalent to the ShouldSerialize* methods for deserialization.
I know I can write a custom converter, but that seems like overkill for this.
Edit:
Here's a little more context. The reason behind this is my class looks like:
public class Address : IAddress
{
/// <summary>
/// Gets or sets the two character country code
/// </summary>
[JsonProperty("countryCode")]
[Required]
public string CountryCode { get; set; }
/// <summary>
/// Gets or sets the country code, and province or state code delimited by a vertical pipe: <c>US|MI</c>
/// </summary>
[JsonProperty("countryProvinceState")]
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("provinceState")]
[Required]
public string ProvinceState { get; set; }
}
I need the CountryProvinceState
property for the request, but I don't want it to deserialize back and trigger the setter logic.
Apply a [JsonIgnore] attribute to the property that you do not want to be serialized.
JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object). If you serialize this result it will generate a text with the structure and the record returned.
JsonPropertyAttribute indicates that a property should be serialized when member serialization is set to opt-in. It includes non-public properties in serialization and deserialization. It can be used to customize type name, reference, null, and default value handling for the property value.
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);
In your question you have a simple string property. But it's a bit more complicated when you have an object. The solution with .Writeable = false
will not work, as deserialization will go to properties of an object. Consider the following code:
public class Constants
{
public Address Headquarters { get; set; }
public static Constants Instance = new Constants
{
Headquarters = new Address { Street = "Baker Street" }
};
}
public class Address
{
public string Street { get; set; }
}
public class Data
{
[GetOnlyJsonProperty]
// we want this to be included in the response, but not deserialized back
public Address HqAddress { get { return Constants.Instance.Headquarters; } }
}
// somewhere in your code:
var data = JsonConvert.DeserializeObject<Data>("{'HqAddress':{'Street':'Liverpool Street'}}", settings);
Now JSON will still not try to create a new Addreess
object for HqAddress
property, as it only has getter. But then (even though .Writeable == false
) it goes deeper and deserializes Street
property, setting "Liverpool Street" into Constants.Instance.Heqdquarters
object, overwriting data in Constants of your application.
Solution is:
In a new version of Newtonsoft.JSON (I tried in v10), there is a new property ShouldDeserialize
. So the resolver should be:
public class GetOnlyContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property != null) // Change here (1)
{
var attributes = property.AttributeProvider.GetAttributes(typeof(GetOnlyJsonPropertyAttribute), true);
if (attributes != null && attributes.Count > 0)
property.ShouldDeserialize = (a) => false; // Change here (2)
}
return property;
}
}
(1) I removed the condition for && property.Writeable
, so it processes the HqAddress
and skips deserialization for a full tree.
(2) ShouldDeserialize
is a predicate, called on every object to deserialize. So you can conditionally skip only some properties. But here I made it simple for example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With