Serialize Property, but Do Not Deserialize Property in Json.Net
Solution 1:
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);
Solution 2:
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.