C
C#2y ago
pticrix

✅ JSON Contract : modifying the value of a property, using System.Text.Json 7

Hello! I'm trying to encrypt only certain fields in a DTO before serializing them, using an attribute in the class definition. The attribute part I got the hang of, however I'm uncertain about how to go about modifying the value of a given property. Here's what I've been doing, trying to follow the tips from this dev blog : https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-7/ - extend the DefaultJsonTypeInfoResolver class - override the GetTypeInfo(Type, JsonSerializerOptions) method - in that method, 'reject' anything that isn't of Kind JsonTypeInfoKind.Object - iterate on the JsonPropertyInfo list returned by JsonTypeInfo.Properties  - check each of the JsonPropertyInfo.AttributeProvider to see if they are ICustomAttributeProvider and if my custom attribute is defined in it. Once I've confirmed that, that is where I'm kinda lost. It's probably dumb, but I haven't managed yet to find what to do from here. I'm thinking either : - I need to change the delegate method of JsonPropertyInfo.Get and JsonPropertyInfo.Set or - I need to tell it here and there to take the property value and to pass it through my encryption method. Anyone here could point me to the correct way to proceed? Current code :
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
JsonTypeInfo typeInfo = base.GetTypeInfo(type, options);
if (typeInfo.Kind != JsonTypeInfoKind.Object) return typeInfo;

foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
{
if (propertyInfo.AttributeProvider is ICustomAttributeProvider provider &&
provider.IsDefined(typeof(JsonEncryptAttribute), inherit: true))
{
# todo : Unsure how to proceed here.
}
}
return typeInfo;
}
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
JsonTypeInfo typeInfo = base.GetTypeInfo(type, options);
if (typeInfo.Kind != JsonTypeInfoKind.Object) return typeInfo;

foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
{
if (propertyInfo.AttributeProvider is ICustomAttributeProvider provider &&
provider.IsDefined(typeof(JsonEncryptAttribute), inherit: true))
{
# todo : Unsure how to proceed here.
}
}
return typeInfo;
}
Any insight appreciated.
1 Reply
pticrix
pticrixOP2y ago
Solved it like a big boy.
[AttributeUsage(AttributeTargets.Property)]
public class JsonEncryptAttribute : Attribute
{
}

public class EncryptedStringPropertyResolver : DefaultJsonTypeInfoResolver
{

private readonly byte[] _encKey;
private readonly byte[] _encIV;

public EncryptedStringPropertyResolver(byte[] encKey, byte[] encIV)
{
_encKey = encKey;
_encIV = encIV;
}


public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
JsonTypeInfo typeInfo = base.GetTypeInfo(type, options);
if (typeInfo.Kind != JsonTypeInfoKind.Object) return typeInfo;

foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
{
if (propertyInfo.AttributeProvider is { } provider &&
provider.IsDefined(typeof(JsonEncryptAttribute), inherit: true))
{
// serialization
propertyInfo.Get = obj =>
{
PropertyInfo property = typeInfo.Type.GetProperty(propertyInfo.Name); // linking JsonProperty with Property, in order to access the field
return property == null ? null : Encryption.Encrypt(property.GetValue(obj).ToString(), _encKey, _encIV);
};

// deserialization
propertyInfo.Set = (_, val) =>
Encryption.Decrypt(val.ToString(), _encKey, _encIV);

}
}
return typeInfo;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class JsonEncryptAttribute : Attribute
{
}

public class EncryptedStringPropertyResolver : DefaultJsonTypeInfoResolver
{

private readonly byte[] _encKey;
private readonly byte[] _encIV;

public EncryptedStringPropertyResolver(byte[] encKey, byte[] encIV)
{
_encKey = encKey;
_encIV = encIV;
}


public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
JsonTypeInfo typeInfo = base.GetTypeInfo(type, options);
if (typeInfo.Kind != JsonTypeInfoKind.Object) return typeInfo;

foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
{
if (propertyInfo.AttributeProvider is { } provider &&
provider.IsDefined(typeof(JsonEncryptAttribute), inherit: true))
{
// serialization
propertyInfo.Get = obj =>
{
PropertyInfo property = typeInfo.Type.GetProperty(propertyInfo.Name); // linking JsonProperty with Property, in order to access the field
return property == null ? null : Encryption.Encrypt(property.GetValue(obj).ToString(), _encKey, _encIV);
};

// deserialization
propertyInfo.Set = (_, val) =>
Encryption.Decrypt(val.ToString(), _encKey, _encIV);

}
}
return typeInfo;
}
}
Note that the Encryption class is a custom class, not one from the Framework.
Want results from more Discord servers?
Add your server