-
We're trying to abide by the DDD "rules" and have our properties use private setters so the entity is responsible for deciding if/when/how the value gets updated. However, when retrieving from the cache, those properties don't get populated upon deserialization. Is there some cool configuration setting I can use to make this magically work with private setters? 🤞🙏😬 |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
For those interested, I got it figured out. The Issue:I am using the Possible Solutions:
My Solution:I didn't want to decorate all of my properties or even all of my classes with an attribute. I also didn't want to use init-only properties because "anyone" can just new-up a class and set the properties to whatever they want. Besides, EF Core can handle private setters, why can't this?! So I created a modifier that includes the public properties with private setters. Example usage: .AddFusionCacheSystemTextJsonSerializer(new JsonSerializerOptions
{
TypeInfoResolver =
new DefaultJsonTypeInfoResolver { Modifiers = { IncludePrivateSetters<BaseEntity> } }
}) Implementation:
public static void IncludePrivateSetters<T>(JsonTypeInfo jsonTypeInfo) where T : class
{
if (jsonTypeInfo.Kind != JsonTypeInfoKind.Object)
{
return;
}
if (jsonTypeInfo.Type != typeof(T) && jsonTypeInfo.Type.BaseType != typeof(T))
{
return;
}
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;
var allProps = jsonTypeInfo.Type.GetProperties(flags).ToList();
// Need to get the BaseType properties separately here because getting them from .Type doesn't include
// the BaseType's private setters or their .SetMethod but the MS docs don't say that yet: https://github.com/dotnet/dotnet-api-docs/issues/4837
allProps.AddRange(jsonTypeInfo.Type.BaseType?.GetProperties(flags) ?? Array.Empty<PropertyInfo>());
var propsWithPrivateSetters = allProps.Where(x => x.SetMethod?.IsPrivate == true);
foreach (var property in propsWithPrivateSetters)
{
var jsonProp =
jsonTypeInfo.Properties.First(x =>
x.Name.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase));
jsonTypeInfo.Properties.Remove(jsonProp);
var jsonPropertyInfo = jsonTypeInfo.CreateJsonPropertyInfo(property.PropertyType, property.Name);
jsonPropertyInfo.Get = property.GetValue;
jsonPropertyInfo.Set = property.SetValue;
jsonTypeInfo.Properties.Add(jsonPropertyInfo);
}
} |
Beta Was this translation helpful? Give feedback.
-
Hi @mwasson74 and thanks for using FusionCache! Sorry for the delay, but it has been quite a busy period recently, also with a big new version of FusionCache coming out soon that has been quite daunting to tame 😅 Anyway, as you correctly guessed problems related to serialization/deserialization are only related to the serializer you decided to use, so the answer lies in one of their option. Thanks for posting the answer and sharing it with the community, maybe somebody else will need this! |
Beta Was this translation helpful? Give feedback.
For those interested, I got it figured out.
The Issue:
I am using the
SystemTextJsonSerializer
and System.Text.Json doesn't include public properties with private setters when deserializing.Possible Solutions:
[JsonInclude]
per the docsMy Solution:
I didn't want to decorate all of my properties or even all of my classes with an attribute. I also didn't want to use init-only properties because "anyone" can just new-up a class and set the properties to whatever they want. Besides, EF Core can handle private setters, why can't this?!
So I created a modi…