Reputation: 2251
We are using .NET Core 3.1
. We have a custom JSON converter for DateTime
and DateTime?
properties.
JsonDateTimeConverter.cs
public class JsonDateTimeConverter : DateTimeConverterBase
{
public override bool CanConvert(Type objectType)
{
// I want to return false for object properties which have attribute "TimeZoneIgnore"
return objectType == typeof(DateTime) || objectType == typeof(DateTime?);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// convert datetime to timezone
DateTime? dateTime = (value as DateTime?).ConvertToTimeZone("CEST");
writer.WriteValue(dateTime);
writer.Flush();
}
}
TimeZoneIgnore.cs
[AttributeUsage(AttributeTargets.Property)]
public class TimeZoneIgnore : Attribute { }
Bank.cs
public class Bank
{
public string Name { get; set; }
public DateTime ConvertThis { get; set; }
[TimeZoneIgnore]
public DateTime DontConvertThis { get; set; }
}
TestController.cs
[HttpGet]
public IActionResult Test123()
{
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new JsonDateTimeConverter());
return Json(new Bank()
{
Name = "Test bank",
ConvertThis = new DateTime(2020, 8, 18, 15, 7, 1),
DontConvertThis = new DateTime(2020, 8, 18, 15, 7, 1)
}, settings);
}
How can I return false
in CanConvert(Type objectType)
for object properties with TimeZoneIgnore
attribute?
Upvotes: 4
Views: 2000
Reputation: 129667
A JsonConverter
doesn't have the context to determine which property it is being applied to, so there is not an easy way to get the attributes from within it. On the other hand, a ContractResolver
does have the context information, because it is responsible for mapping JSON properties to class properties. It turns out you can also use a ContractResolver
to programmatically apply or remove JsonConverters
.
So, instead of applying your JsonDateTimeConverter
globally in settings, you can use a custom ContractResolver
to apply it conditionally based on the presence or absence of the [TimeZoneIgnore]
attribute. Here is the code you would need for the resolver:
public class ConditionalDateTimeResolver : DefaultContractResolver
{
static readonly JsonConverter DateTimeConverter = new JsonDateTimeConverter();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
if (DateTimeConverter.CanConvert(prop.PropertyType) &&
!prop.AttributeProvider.GetAttributes(typeof(TimeZoneIgnore), true).Any())
{
prop.Converter = DateTimeConverter;
}
return prop;
}
}
To use the resolver, add it to the JsonSerializerSettings
instead of adding your converter:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new ConditionalDateTimeResolver();
// settings.Converters.Add(new JsonDateTimeConverter()); <-- remove this line
Here is a working demo: https://dotnetfiddle.net/8LBZ4S
Upvotes: 3