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.