Custom attribute handling in Json.Net - c#

My goal is to serialize properties that don't have any attributes and properties which have a specific custom attribute.
For the following class:
public class Msg
{
public long Id { get; set; }
[CustomAttributeA]
public string Text { get; set; }
[CustomAttributeB]
public string Status { get; set; }
}
When I call a method Serialize(object, CustomAttributeA), I want to have the following output:
{
"Id" : someId,
"Text" : "some text"
}
And when I call Serialize(object, CustomAttributeB), I want to have following:
{
"Id" : someId,
"Status" : "some status"
}
I have read that it's possible to achieve this by creating a custom ContractResolver, but in this case must I create two separate contract resolvers?

You do not need two separate resolvers to achieve your goal. Just make the custom ContractResolver generic, where the type parameter represents the attribute you are looking for when serializing.
For example:
public class CustomResolver<T> : DefaultContractResolver where T : Attribute
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
foreach (JsonProperty prop in list)
{
PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
if (pi != null)
{
// if the property has any attribute other than
// the specific one we are seeking, don't serialize it
if (pi.GetCustomAttributes().Any() &&
pi.GetCustomAttribute<T>() == null)
{
prop.ShouldSerialize = obj => false;
}
}
}
return list;
}
}
Then, you can make a helper method to create the resolver and serialize your object:
public static string Serialize<T>(object obj) where T : Attribute
{
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new CustomResolver<T>(),
Formatting = Formatting.Indented
};
return JsonConvert.SerializeObject(obj, settings);
}
When you want to serialize, call the helper like this:
string json = Serialize<CustomAttributeA>(msg);
Demo fiddle: https://dotnetfiddle.net/bRHbLy

Related

Deserializing json - mapping single property with no direct json match

I am trying to deserialize an existing JSON structure to into an object composed of a set of models. The naming in these models are not consistent and I was specifically asked to not change them (renaming, adding attributes, etc).
So, given this Json text (just a small sample):
{
"parameter": {
"alarms": [
{
"id": 1,
"name": "alarm1",
"type": 5,
"min": 0,
"max": 2
}],
"setting-active": true,
"setting-oneRun": true
}
}
would need to be mapped into these models:
public class Alarm
{
public int AlarmId { get; set; }
public string AlarmName { get; set; }
public AlarmType RbcType { get; set; }
public int MinimumTolerated { get; set; }
public int MaximumTolerated { get; set; }
}
public class Setting
{
public bool Active { get; set; }
public bool OneRun { get; set; }
}
public class Parameter
{
public List<Alarm> Alarms { get; set; }
public Setting ParameterSetting { get; set; }
}
So far, im writing a class that extends DefaultContractResolver and overrides maps property names.
MyCustomResolver so far:
public class MyCustomResolver : DefaultContractResolver
{
private Dictionary<string, string>? _propertyMappings;
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
//ModelMappings is a static class that will return a dictionary with mappings per ObjType being deserialized
_propertyMappings = ModelMappings.GetMapping(type);
return base.CreateProperties(type, memberSerialization);
}
protected override string ResolvePropertyName(string propertyName)
{
if (_propertyMappings != null)
{
_propertyMappings.TryGetValue(propertyName, out string? resolvedName);
return resolvedName ?? base.ResolvePropertyName(propertyName);
}
return base.ResolvePropertyName(propertyName);
}
}
Code that Im using to deserialize:
var settings = new JsonSerializerSettings();
settings.DateFormatString = "YYYY-MM-DD";
settings.ContractResolver = new MyCustomResolver();
Parameter p = JsonConvert.DeserializeObject<Parameter>(jsonString, settings);
So I reached a point I need to somehow map the properties in Parameter to values located in the prev json node ("setting-active", "setting-oneRun"). I need to tell the deserializer where these values are.
Can this be done using an extension of DefaultContractResolver ?
I appreciate any tips pointing in the right direction
You can apply ModelMappings.GetMapping(objectType) in DefaultContractResolver.CreateObjectContract():
public class MyCustomResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
var overrides = ModelMappings.GetMapping(objectType);
if (overrides != null)
{
foreach (var property in contract.Properties.Concat(contract.CreatorParameters))
{
if (property.UnderlyingName != null && overrides.TryGetValue(property.UnderlyingName, out var name))
property.PropertyName = name;
}
}
return contract;
}
}
Notes:
By applying the mappings in CreateObjectContract() you can remap both property names and creator parameter names.
Since the contract resolver is designed to resolve contracts for all types, storing a single private Dictionary<string, string>? _propertyMappings; doesn't really make sense.
Unlike your previous question, your current question shows properties from a nested c# object ParameterSetting getting percolated up to the parent object Parameter. Since a custom contract resolver is designed to generate the contract for a single type, it isn't suited to restructuring data between types. Instead, consider using a DTO or converter + DTO in such situations:
public class ParameterConverter : JsonConverter<Parameter>
{
record ParameterDTO(List<Alarm> alarms, [property: JsonProperty("setting-active")] bool? Active, [property: JsonProperty("setting-oneRun")] bool? OneRun);
public override void WriteJson(JsonWriter writer, Parameter? value, JsonSerializer serializer)
{
var dto = new ParameterDTO(value!.Alarms, value.ParameterSetting?.Active, value.ParameterSetting?.OneRun);
serializer.Serialize(writer, dto);
}
public override Parameter? ReadJson(JsonReader reader, Type objectType, Parameter? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var dto = serializer.Deserialize<ParameterDTO>(reader);
if (dto == null)
return null;
existingValue ??= new ();
existingValue.Alarms = dto.alarms;
if (dto.Active != null || dto.OneRun != null)
existingValue.ParameterSetting = new () { Active = dto.Active.GetValueOrDefault(), OneRun = dto.OneRun.GetValueOrDefault() };
return existingValue;
}
}
If your "real" model is too complex to define a DTO, you could create a JsonConverter<Paramater> that (de)serializes the JSON into an intermediate JToken hierarchy, then restructures that. See e.g. this answer to Can I serialize nested properties to my class in one operation with Json.net?.
In some cases, the custom naming of your properties is just camel casing. To camel case property names without the need for explicit overrides, set MyCustomResolver.NamingStrategy to CamelCaseNamingStrategy e.g. as follows:
var settings = new JsonSerializerSettings
{
DateFormatString = "YYYY-MM-DD",
// Use CamelCaseNamingStrategy since many properties in the JSON are just camel-cased.
ContractResolver = new MyCustomResolver { NamingStrategy = new CamelCaseNamingStrategy() },
Converters = { new ParameterConverter() },
};
Demo fiddle here.
I think that the best way to "KEEP IT SIMPLE", you need to define an object that has exactly the properties of the json. Then you can use a library like "Automapper" to define rules of mapping between the "json object" and the "business object".

System.Text.Json - Use custom JsonConverter conditionally depending on field attribute

I have a custom attribute [Foo]
implemented as follows:
public class FooAttribute
: Attribute
{
}
Now I want to use the System.Text.Json.JsonSerializer to step into each field that has that attribute, in order to manipulate how is serialized and deserialized.
For example, if I have the following class
class SampleInt
{
[Foo]
public int Number { get; init; }
public int StandardNumber { get; init; }
public string Text { get; init; }
}
when I serialize an instance of this class, I want a custom int JsonConverter to apply only for that field.
public class IntJsonConverter
: JsonConverter<int>
{
public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// do whatever before reading if the text starts with "potato". But this should be triggered only if destination type has the Foo attribute. How?
return reader.GetInt32();
}
public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
{
writer.WriteStringValue("potato" + value.ToString());
}
}
so that the serialization for
var sample =
new SampleInt
{
Number = 123,
StandardNumber = 456
Text = "bar"
};
like this
var serializeOptions = new JsonSerializerOptions();
var serializeOptions.Converters.Add(new IntJsonConverter());
var resultJson = JsonSerializer.Serialize(sample, serializeOptions);
results on the following json
{
"number": "potato123",
"standardNumber": 456,
"text": "bar"
}
and not in
{
"number": "potato123",
"standardNumber": "potato456",
"text": "bar"
}
In a similar manner, I want the deserialization to be conditional, and only use the custom converter if the destination field has the [Foo] attribute.
With Newtonsoft, this is possible using Contract Resolvers and overriding CreateProperties method like this.
public class SerializationContractResolver
: DefaultContractResolver
{
private readonly ICryptoTransform _encryptor;
private readonly FieldEncryptionDecryption _fieldEncryptionDecryption;
public SerializationContractResolver(
ICryptoTransform encryptor,
FieldEncryptionDecryption fieldEncryptionDecryption)
{
_encryptor = encryptor;
_fieldEncryptionDecryption = fieldEncryptionDecryption;
NamingStrategy = new CamelCaseNamingStrategy();
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
foreach (var jsonProperty in properties)
{
var hasAttribute = HasAttribute(type, jsonProperty);
if (hasAttribute)
{
var serializationJsonConverter = new MyJsonConverter();
jsonProperty.Converter = serializationJsonConverter;
}
}
return properties;
}
private bool HasAttribute(Type type, JsonProperty jsonProperty)
{
var propertyInfo = type.GetProperty(jsonProperty.UnderlyingName);
if (propertyInfo is null)
{
return false;
}
var hasAttribute =
propertyInfo.CustomAttributes
.Any(x => x.AttributeType == typeof(FooAttribute));
var propertyType = propertyInfo.PropertyType;
var isSimpleValue = propertyType.IsValueType || propertyType == typeof(string);
var isSupportedField = isSimpleValue && hasPersonalDataAttribute;
return isSupportedField;
}
}
But I don't want to use Newtonsoft. I want to use the new dotnet System.Text.Json serializer. Is it possible to use it in a similar granular way?

Using property attributes to define which JsonConverter to use

I have a need to specify a JsonConverter for properties which are decorated with a specific attribute, in this case [DataType(DataType.PostalCode)].
I already have a custom JsonConverter for which I have set the CanConvert method as follows:
public override bool CanConvert(Type objectType) => objectType == typeof(string);
How can I make sure the PostcodeJsonConverter is used instead when the API encounters a PostalCode property?
[DataType(DataType.PostalCode)]
public string Postcode { get; set; }
I've tried the following but I suspect the DataType attribute is not available at this point.
public override bool CanConvert(Type objectType) =>
objectType == typeof(string) &&
objectType.GetCustomAttributes(true)
.OfType<DataTypeAttribute>()
.Any(dta => dta.DataType == DataType.PostalCode);
Do I need to decorate my model as follows instead?
[DataType(DataType.PostalCode)]
[JsonConverter(typeof(PostcodeJsonConverter))]
public string Postcode { get; set; }
You can make a custom ContractResolver that looks for your DataType attribute on each property and maps the values to the appropriate converter. Here is the code you would need:
public class DataTypeResolver : DefaultContractResolver
{
private Dictionary<DataType, JsonConverter> ConvertersByDataType { get; set; }
public DataTypeResolver()
{
// Adjust this list to match your actual data types and converters
ConvertersByDataType = new Dictionary<DataType, JsonConverter>
{
{ DataType.PostalCode, new PostalCodeConverter() },
{ DataType.PhoneNumber, new PhoneNumberConverter() },
};
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
var att = prop.AttributeProvider.GetAttributes(true).OfType<DataTypeAttribute>().FirstOrDefault();
if (att != null)
{
JsonConverter converter;
if (ConvertersByDataType.TryGetValue(att.DataType, out converter))
{
prop.Converter = converter;
}
}
return prop;
}
}
Then pass the resolver to SerializeObject and/or DeserializeObject via the settings:
var settings = new JsonSerializerSettings
{
ContractResolver = new DataTypeResolver()
};
string json = JsonConvert.SerializeObject(yourObject, settings);
Here is a working demo: https://dotnetfiddle.net/k1kWv5
You can add Converters to the JsonSerializerSettings. So instead of decorating everything, you may as well add your PostcodeJsonConverter there (depending on how often it is used, a decorator may be better though):
For aspnet core defaults:
services.AddMvc().AddJsonOptions(o => o.SerializerSettings.Converters.Add(new PostcodeJsonConverter()))
For JsonConvert:
JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
Converters = { new PostcodeJsonConverter() }
});

Validate response to filter array objects which are having no elements

How can I filter out the array objects which are having 0 elements from the ASP.NET Web API Model.
Ex: I'm am using the below method to filter null objects.
using Newtonsoft.Json;
public string FaxWork { get; set; }
[JsonProperty(PropertyName = "phoneWork", NullValueHandling = NullValueHandling.Ignore)]
How can I use something like above in order to filter out [] empty array objects?
Ex:
"postalAddress": [],
"electronicAddress": []
You can accomplish this using the conditional property serialization functionality of Json.NET.
If you just want to ignore a single member when its array value is empty, add a ShouldSerialize{PropertyName}() method to your class that returns false when you don't want it serialized, e.g.:
public class RootObject
{
public string[] PostalAddress { get; set; }
public bool ShouldSerializePostalAddress() { return PostalAddress != null && PostalAddress.Length > 0; }
}
If you need to do this for many different collection-valued members of many different types, you can create a custom contract resolver that automatically generates a ShouldSerialize predicate for all of then:
public class SkipEmptyCollectionsContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization)
.AddShouldSerializeEmptyCollections(this);
return property;
}
}
public static class JsonPropertyExtensions
{
public static JsonProperty AddShouldSerializeEmptyCollections(this JsonProperty property, IContractResolver resolver)
{
if (property == null)
throw new ArgumentNullException();
if ((typeof(IEnumerable).IsAssignableFrom(property.PropertyType) || property.PropertyType.IsAssignableFrom(typeof(IEnumerable)))
&& property.PropertyType != typeof(string)
&& property.Readable)
{
Predicate<object> shouldSerialize = (parent) =>
{
var value = property.ValueProvider.GetValue(parent);
if (value == null || value is string)
return true; // null properties are filtered by the NullValueHandling setting.
var contract = resolver.ResolveContract(value.GetType());
if (contract is JsonArrayContract)
{
return (value as IEnumerable).Any();
}
return true;
};
var oldShouldSerialize = property.ShouldSerialize;
if (oldShouldSerialize == null)
property.ShouldSerialize = shouldSerialize;
else
property.ShouldSerialize = (o) => shouldSerialize(o) && oldShouldSerialize(o);
}
return property;
}
}
public static class EnumerableExtensions
{
public static bool Any(this IEnumerable enumerable)
{
if (enumerable == null)
return false;
if (enumerable is ICollection)
{
return ((ICollection)enumerable).Count > 0;
}
var enumerator = enumerable.GetEnumerator();
using (enumerator as IDisposable)
{
return enumerator.MoveNext();
}
}
}
Then serialize using JsonSerializerSettings such as the following, which also enables camel casing of names:
var settings = new JsonSerializerSettings
{
ContractResolver = new SkipEmptyCollectionsContractResolver { NamingStrategy = new CamelCaseNamingStrategy() },
NullValueHandling = NullValueHandling.Ignore,
};
If you want to conditionally filter out empty collections using attributes, you could do so with the following contract resolver and attribute:
public enum EmptyArrayHandling
{
Include = 0,
Ignore = 1,
}
[System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class JsonPropertyExtensionsAttribute : System.Attribute
{
public EmptyArrayHandling EmptyArrayHandling { get; set; }
}
public class ConditionallySkipEmptyCollectionsContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
var attr = property.AttributeProvider.GetAttributes(typeof(JsonPropertyExtensionsAttribute), false).Cast<JsonPropertyExtensionsAttribute>().FirstOrDefault();
if (attr != null && attr.EmptyArrayHandling == EmptyArrayHandling.Ignore)
property = property.AddShouldSerializeEmptyCollections(this);
return property;
}
}
Then apply to your members as follows:
public class RootObject
{
[JsonPropertyExtensions(EmptyArrayHandling = EmptyArrayHandling.Ignore)]
public string[] PostalAddress { get; set; }
}
Note that if your "collection" is actually a complex LINQ query, the ShouldSerialize method will have to enumerate the first element of the query to see if it is empty, which may lead to poor performance because the query will get evaluated twice. To avoid this, you can evaluate the entire query as a list before serializing.
You may want to cache the contract resolver for best performance.

NewtonSoft add JSONIGNORE at runTime

Am looking to Serialize a list using NewtonSoft JSON and i need to ignore one of the property while Serializing and i got the below code
public class Car
{
// included in JSON
public string Model { get; set; }
// ignored
[JsonIgnore]
public DateTime LastModified { get; set; }
}
But am using this Specific class Car in many places in my application and i want to Exclude the option only in one place.
Can i dynamically add [JsonIgnore] in the Specific Place where i need ? How do i do that ?
No need to do the complicated stuff explained in the other answer.
NewtonSoft JSON has a built-in feature for that:
public bool ShouldSerializeINSERT_YOUR_PROPERTY_NAME_HERE()
{
if(someCondition){
return true;
}else{
return false;
}
}
It is called "conditional property serialization" and the documentation can be found here.
Warning: first of all, it is important to get rid of [JsonIgnore] above your {get;set;} property. Otherwise it will overwrite the ShouldSerializeXYZ behavior.
I think it would be best to use a custom IContractResolver to achieve this:
public class DynamicContractResolver : DefaultContractResolver
{
private readonly string _propertyNameToExclude;
public DynamicContractResolver(string propertyNameToExclude)
{
_propertyNameToExclude = propertyNameToExclude;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
// only serializer properties that are not named after the specified property.
properties =
properties.Where(p => string.Compare(p.PropertyName, _propertyNameToExclude, true) != 0).ToList();
return properties;
}
}
The LINQ may not be correct, I haven't had a chance to test this. You can then use it as follows:
string json = JsonConvert.SerializeObject(car, Formatting.Indented,
new JsonSerializerSettings { ContractResolver = new DynamicContractResolver("LastModified") });
Refer to the documentation for more information.
Based on #Underscore post above, I created a list of properties to exclude on serialization.
public class DynamicContractResolver : DefaultContractResolver {
private readonly string[] props;
public DynamicContractResolver(params string[] prop) {
this.props = prop;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) {
IList<JsonProperty> retval = base.CreateProperties(type, memberSerialization);
// return all the properties which are not in the ignore list
retval = retval.Where(p => !this.props.Contains(p.PropertyName)).ToList();
return retval;
}
}
Use:
string json = JsonConvert.SerializeObject(car, Formatting.Indented,
new JsonSerializerSettings { ContractResolver = new DynamicContractResolver("ID", "CreatedAt", "LastModified") });
With the reference Dynamically rename or ignore properties without changing the serialized class we can achieve JsonIgnore at run time. It's a workable solution.
Consider Person Class for example:
public class Person
{
// ignore property
[JsonIgnore]
public string Title { get; set; }
// rename property
[JsonProperty("firstName")]
public string FirstName { get; set; }
}
Step 1: Create Class "PropertyRenameAndIgnoreSerializerContractResolver"
public class PropertyRenameAndIgnoreSerializerContractResolver : DefaultContractResolver
{
private readonly Dictionary<Type, HashSet<string>> _ignores;
private readonly Dictionary<Type, Dictionary<string, string>> _renames;
public PropertyRenameAndIgnoreSerializerContractResolver()
{
_ignores = new Dictionary<Type, HashSet<string>>();
_renames = new Dictionary<Type, Dictionary<string, string>>();
}
public void IgnoreProperty(Type type, params string[] jsonPropertyNames)
{
if (!_ignores.ContainsKey(type))
_ignores[type] = new HashSet<string>();
foreach (var prop in jsonPropertyNames)
_ignores[type].Add(prop);
}
public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
{
if (!_renames.ContainsKey(type))
_renames[type] = new Dictionary<string, string>();
_renames[type][propertyName] = newJsonPropertyName;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (IsIgnored(property.DeclaringType, property.PropertyName))
{
property.ShouldSerialize = i => false;
property.Ignored = true;
}
if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
property.PropertyName = newJsonPropertyName;
return property;
}
private bool IsIgnored(Type type, string jsonPropertyName)
{
if (!_ignores.ContainsKey(type))
return false;
return _ignores[type].Contains(jsonPropertyName);
}
private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
{
Dictionary<string, string> renames;
if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
{
newJsonPropertyName = null;
return false;
}
return true;
}
}
Step 2: Add code in your method where Jsonignore want to apply
var person = new Person();
var jsonResolver = new PropertyRenameAndIgnoreSerializerContractResolver();
jsonResolver.IgnoreProperty(typeof(Person), "Title");
jsonResolver.RenameProperty(typeof(Person), "FirstName", "firstName");
var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = jsonResolver;
var json = JsonConvert.SerializeObject(person, serializerSettings);
With respect to all correct answers I would like to add something. When you have nested properties with the same name so ignoring will effect on all properties with the same name. If you like to ignore a specific property you can do something like this:
public class DynamicContractResolver : DefaultContractResolver
{
private readonly string[] props;
public DynamicContractResolver(params string[] prop)
{
this.props = prop;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> retval = base.CreateProperties(type, memberSerialization);
return retval.Where(p => !this.props.Contains(p.DeclaringType.FullName + "." + p.PropertyName)).ToList();
}
}
then when you want to use it you can say:
var values = await _dbContext
.Set<EntityName>()
.Where(...).ToList();
var json = JsonConvert.SerializeObject(values, Formatting.Indented,
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new DynamicContractResolver("Entities.Contact.Address1","Entities.User.Name","Entities.Event.Name")
});
The Address1 will be ignored in Contact not anywhere else.
Try this:
public static void IgnoreProperty<T, TR>(this T parameter, Expression<Func<T, TR>> propertyLambda)
{
var parameterType = parameter.GetType();
var propertyName = propertyLambda.GetReturnedPropertyName();
if (propertyName == null)
{
return;
}
var jsonPropertyAttribute = parameterType.GetProperty(propertyName).GetCustomAttribute<JsonPropertyAttribute>();
jsonPropertyAttribute.DefaultValueHandling = DefaultValueHandling.Ignore;
}
public static string GetReturnedPropertyName<T, TR>(this Expression<Func<T, TR>> propertyLambda)
{
var member = propertyLambda.Body as MemberExpression;
var memberPropertyInfo = member?.Member as PropertyInfo;
return memberPropertyInfo?.Name;
}
So you can do this:
carObject.IgnoreProperty(so => so.LastModified);
Based on the accepted answer it would be like:
[JsonIgnore]
public bool JsonIgnore { get; set; }
public bool ImageModified { get; set; }
public bool ShouldSerializeImageModified() => !JsonIgnore;
Whenever JsonIgnore is set to true it means that ImageModified won't be serialized, and JsonIgnore is ignored because of [JsonIgnore].
If there is a need to write code this way, it might be an indication of poor design. Probably there needs to be a DTO or ViewModel in the system, unless you want to dynamically disable/enable serialization of some properties.

Categories

Resources