On one of my projects we are using event sourcing as our data persistence strategy. Based on the event stream I build projections using read models.
I prefer to keep my projected read model immutable but turns out that JSON.NET fails to deserialize the state. All properties retain their default values.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Product | |
{ | |
public Guid Id { get; private set; } | |
public string Name { get; private set; } | |
} |
A solution is to create a custom contract resolver that uses reflection to set the property values:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal class ResolvePrivateSetters : DefaultContractResolver | |
{ | |
protected override JsonProperty CreateProperty( | |
MemberInfo member, | |
MemberSerialization memberSerialization) | |
{ | |
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; | |
} | |
} |
Don't forget to apply this contract resolver using the JsonSerializerSettings:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var settings = new JsonSerializerSettings() | |
{ | |
ContractResolver= new ResolvePrivateSetters() | |
}; | |
JsonConvert.DeserializeObject(json, settings); |