-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
I'm trying to migrate some of our Newtonsoft.Json functionality over to System.Text.Json and we used to have code that would opt-in to serialization instead of the opt-out model of the JsonIgnoreAttribute.
The scenario is in a web app that we like to log the request object when validation fails, but just certain properties to avoid any PII/PCI issues.
We can't use the JsonIgnoreAttribute for two reasons:
1- Adding the attribute will stop the serializer used by ASP.NET Core from deserializing the HTTP request into an object. We still want this. We want that when we serialize it with our own JsonSerializer we add our customization to only allow certain properties.
2- For security reasons we want to have an opt-in model instead of opt-out in case a new sensitive property is added but the attribute is forgotten. We want to avoid getting this data into our logs.
This is our code simplified:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class LogAttribute : Attribute
{
}
public class PersonApiRequest
{
[Log] // <-- serialization opt-in attribute
public int Id { get; set; }
[RegularExpression("SomeRegex")]
public string Name { get; set; }
[RegularExpression("SomeRegex")]
public string Ssn { get; set; }
}
public class LogContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
var attributes = property.AttributeProvider.GetAttributes(typeof(LogAttribute), true);
property.Ignored = attributes.Count == 0;
return property;
}
}
public class PersonController : Controller
{
private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings { ContractResolver = new LogContractResolver() };
[HttpPost]
public IActionResult Index([FromBody]PersonApiRequest apiRequest)
{
if (!ModelState.IsValid)
{
var modelSerialized = JsonConvert.SerializeObject(apiRequest, SerializerSettings);
_logger.LogWarning("Invalid {Request}", modelSerialized);
return BadRequest(ModelState);
}
...
}
}