I have the following class structure:
[JsonObject]
public class Polygon : IEnumerable<Point>
{
public List<Point> Vertices { get; set; }
public AxisAlignedRectangle Envelope { get; set; }
}
public class AxisAlignedRectangle : Polygon {
public double Left { get; set; }
...
}
I am serializing the Polygon class, but when I do, I get a JsonSerializationException, with the message
Self referencing loop detected for property 'Envelope' with type 'MyNamespace.AxisAlignedRectangle'.
If I add [JsonObject(IsReference = true)] (as described here) to AxisAlignedRectangle, the code runs fine, but I get an auto-assigned $id field in each instance of AxisAlignedRectangle, and a $ref field when that instance is re-referenced. For example, when I serialize a polygon, I get:
{
Vertices: [ ... ],
Envelope: {
$id: '1',
Left: -5,
...
Vertices: [ ... ],
Envelope: {
$ref: '1'
}
}
}
My desire is to remove the Polygon properties entirely when I serialize an AxisAlignedRectangle. I tried adding a DataContractAttribute to the AxisAlignedRectangle class (along with appropriate DataMemberAttribute attributes), but all the properties of Polygon were still being serialized. This was unexpected, since there is an example in the Json.NET documentation that appears to indicate such an approach should work.
Does anyone know a way to explicitly remove (most importantly) the Envelope property from the resulting Json.NET serialization, when the type being serialized is AxisAlignedRectangle? Thanks.
Most simple way to do it is simply decorate the AxisAlignedRectangle object with [JsonObject(MemberSerialization.OptIn)].
In a sentence, it will serialize only properties decorated with [JsonProperty] attribute.
You can read more here: MemberSerialization Enumeration.
Another option is to decorate the Polygon properties with JsonIgnoreAttribute Class.
I've run into the same thing. The JsonIgnoreAttribute is a good solution if a certain property should always be ingored and you have access to the class containing the property. But if you want to determine which properties should be serialized at serialization-time, you can use a ContractResolver.
Here's an implementation that allows you to serialize properties starting with the most derived class and stopping at a given base class. In my case, I wanted to serialize the properties of my custom CMS (EPiServer) page types, but didn't want to serialize all of the built-in properties of the page classes.
public class DerivedClassContractResolver : DefaultContractResolver
{
private Type _stopAtBaseType;
public DerivedClassContractResolver(Type stopAtBaseType)
{
_stopAtBaseType = stopAtBaseType;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
Type originalType = GetOriginalType(type);
IList<JsonProperty> defaultProperties = base.CreateProperties(type, memberSerialization);
List<string> includedProperties = Utilities.GetPropertyNames(originalType, _stopAtBaseType);
return defaultProperties.Where(p => includedProperties.Contains(p.PropertyName)).ToList();
}
private Type GetOriginalType(Type type)
{
Type originalType = type;
//If the type is a dynamic proxy, get the base type
if (typeof(Castle.DynamicProxy.IProxyTargetAccessor).IsAssignableFrom(type))
originalType = type.BaseType ?? type;
return originalType;
}
}
public class Utilities
{
/// <summary>
/// Gets a list of all public instance properties of a given class type
/// excluding those belonging to or inherited by the given base type.
/// </summary>
/// <param name="type">The Type to get property names for</param>
/// <param name="stopAtType">A base type inherited by type whose properties should not be included.</param>
/// <returns></returns>
public static List<string> GetPropertyNames(Type type, Type stopAtBaseType)
{
List<string> propertyNames = new List<string>();
if (type == null || type == stopAtBaseType) return propertyNames;
Type currentType = type;
do
{
PropertyInfo[] properties = currentType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
foreach (PropertyInfo property in properties)
if (!propertyNames.Contains(property.Name))
propertyNames.Add(property.Name);
currentType = currentType.BaseType;
} while (currentType != null && currentType != stopAtBaseType);
return propertyNames;
}
}
This let's me do something like this:
JsonConvert.SerializeObject(page, new JsonSerializerSettings()
{
ContractResolver = new DerivedClassContractResolver(typeof(EPiServer.Core.PageData))
}));
to get the properties I have defined on my own class(es) without getting the slew of properties inherited from EPiServer.Core.PageData. Note: You don't need the GetOriginalType() code if you're not using the Castle DynamicProxy project (which the EPiServer CMS does.)
You can use conditional property serialization, by defining your classes like this:
[JsonObject]
public class Polygon : IEnumerable<Point>
{
public List<Point> Vertices { get; set; }
public AxisAlignedRectangle Envelope { get; set; }
public virtual bool ShouldSerializeEnvelope()
{
return true;
}
}
public class AxisAlignedRectangle : Polygon
{
public double Left { get; set; }
...
public override bool ShouldSerializeEnvelope()
{
return false;
}
}
I have posted the full solution at:
https://github.com/thiagoavelino/VisualStudio_C/blob/master/VisualStudio_C/StackOverFlow/ParsingJason/EnvelopePolygonProblem.cs
In WPF its common to want to ignore Observables
public class TypeOnlyContractResolver<T> : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = instance =>
{
return !property.DeclaringType.AssemblyQualifiedName.Contains("Observable");
};
property.ShouldDeserialize = instance =>
{
return !property.DeclaringType.AssemblyQualifiedName.Contains("Observable");
};
return property;
}
}
This will ignore anything with the base class ObservableObject etc.
Related
I have a custom type derived from the DynamicObject type. This type has fixed properties declared in the type. So it allows the user to provide some required properties in addition to any dynamic properties they want. When I use the JsonConvert.DeserializeObject<MyType>(json) method to deserialize the data for this type, it does not set the declared properties, but those properties are accessible via the object indexer property on the dynamic object. This tells me that it simply treats the object as a dictionary and does not try to call the declared property setters nor is it using them for inferring the property type information.
Has anyone encountered this situation before? Any idea how I can instruct the JsonConvert class to take the declared properties into account when deserializing the object data?
I tried to use a custom JsonConverter, but that requires me to write the complex JSON read and writ methods. I was hoping to find a way inject property contract information by overriding the JsonContractResolver or JsonConverter, etc.
//#define IMPLEMENT_IDICTIONARY
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using Newtonsoft.Json;
namespace ConsoleApp1
{
class Program
{
public class MyDynamicObject : DynamicObject
#if IMPLEMENT_IDICTIONARY
, IDictionary<string, object>
#endif
{
private Dictionary<string, object> m_Members;
public MyDynamicObject()
{
this.m_Members = new Dictionary<string, object>();
}
#if IMPLEMENT_IDICTIONARY
public int Count { get { return this.m_Members.Count; } }
public ICollection<string> Keys => this.m_Members.Keys;
public ICollection<object> Values => this.m_Members.Values;
bool ICollection<KeyValuePair<string, object>>.IsReadOnly => false;
/// <summary>
/// Gets or sets the specified member value.
/// </summary>
/// <param name="memberName">Name of the member in question.</param>
/// <returns>A value for the specified member.</returns>
public object this[string memberName]
{
get
{
object value;
if (this.m_Members.TryGetValue(memberName, out value))
return value;
else
return null;
}
set => this.m_Members[memberName] = value;
}
#endif
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
this.m_Members.TryGetValue(binder.Name, out result);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
this.m_Members[binder.Name] = value;
return true;
}
public override bool TryDeleteMember(DeleteMemberBinder binder)
{
return this.m_Members.Remove(binder.Name);
}
public override IEnumerable<string> GetDynamicMemberNames()
{
var names = base.GetDynamicMemberNames();
return this.m_Members.Keys;
}
#if IMPLEMENT_IDICTIONARY
bool IDictionary<string, object>.ContainsKey(string memberName)
{
return this.m_Members.ContainsKey(memberName);
}
public void Add(string memberName, object value)
{
this.m_Members.Add(memberName, value);
}
public bool Remove(string memberName)
{
return this.m_Members.Remove(memberName);
}
public bool TryGetValue(string memberName, out object value)
{
return this.m_Members.TryGetValue(memberName, out value);
}
public void Clear()
{
this.m_Members.Clear();
}
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> member)
{
((IDictionary<string, object>)this.m_Members).Add(member);
}
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> member)
{
return ((IDictionary<string, object>)this.m_Members).Contains(member);
}
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
((IDictionary<string, object>)this.m_Members).CopyTo(array, arrayIndex);
}
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> member)
{
return ((IDictionary<string, object>)this.m_Members).Remove(member);
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return this.m_Members.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.m_Members.GetEnumerator();
}
#endif
}
public class ProxyInfo
{
public string Server;
public int Port;
}
public class CustomDynamicObject : MyDynamicObject
{
//[JsonProperty] // NOTE: Cannot do this.
public string Name { get; set; }
//[JsonProperty] // NOTE: Cannot do this.
public ProxyInfo Proxy { get; set; }
}
static void Main(string[] args)
{
dynamic obj = new CustomDynamicObject()
{
Name = "Test1",
Proxy = new ProxyInfo() { Server = "http://test.com/", Port = 10102 }
};
obj.Prop1 = "P1";
obj.Prop2 = 320;
string json = JsonConvert.SerializeObject(obj); // Returns: { "Prop1":"P1", "Prop2":320 }
// ISSUE #1: It did not serialize the declared properties. Only the dynamically added properties are serialized.
// Following JSON was expected. It produces correct JSON if I mark the declared properties with
// JsonProperty attribute, which I cannot do in all cases.
string expectedJson = "{ \"Prop1\":\"P1\", \"Prop2\":320, \"Name\":\"Test1\", \"Proxy\":{ \"Server\":\"http://test.com/\", \"Port\":10102 } }";
CustomDynamicObject deserializedObj = JsonConvert.DeserializeObject<CustomDynamicObject>(expectedJson);
// ISSUE #2: Deserialization worked in this case, but does not work once I re-introduce the IDictionary interface on my base class.
// In that case, it does not populate the declared properties, but simply added all 4 properties to the underlying dictionary.
// Neither does it infer the ProxyInfo type when deserializing the Proxy property value and simply bound the JObject token to
// the dynamic object.
}
}
}
I would have expected it to use reflection to resolve the property and its type information like it does for regular types. But it seems as if it simply treats the object as a regular dictionary.
Note that:
I cannot remove the IDictionary<string, object> interface since some of the use-cases in my API rely on the object to be a dictionary, not dynamic.
Adding [JsonProperty] to all declared properties to be serialized is not practical because its derived types are created by other developers and they do not need to care about the persistence mechanism explicitly.
Any suggestions on how I can make it work correctly?
You have a few problems here:
You need to correctly override DynamicObject.GetDynamicMemberNames() as explained in this answer to Serialize instance of a class deriving from DynamicObject class by AlbertK
for Json.NET to be able to serialize your dynamic properties.
(This has already been fixed in the edited version of your question.)
Declared properties do not show up unless you explicitly mark them with [JsonProperty] (as explained in this answer to C# How to serialize (JSON, XML) normal properties on a class that inherits from DynamicObject) but your type definitions are read-only and cannot be modified.
The problem here seems to be that JsonSerializerInternalWriter.SerializeDynamic() only serializes declared properties for which JsonProperty.HasMemberAttribute == true. (I don't know why this check is made there, it would seem to make more sense to set CanRead or Ignored inside the contract resolver.)
You would like for your class to implement IDictionary<string, object>, but if you do, it breaks deserialization; declared properties are no longer populated, but are instead added to the dictionary.
The problem here seems to be that DefaultContractResolver.CreateContract() returns JsonDictionaryContract rather than JsonDynamicContract when the incoming type implements IDictionary<TKey, TValue> for any TKey and TValue.
Assuming you have fixed issue #1, issues #2 and #3 can be handled by using a custom contract resolver such as the following:
public class MyContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
// Prefer JsonDynamicContract for MyDynamicObject
if (typeof(MyDynamicObject).IsAssignableFrom(objectType))
{
return CreateDynamicContract(objectType);
}
return base.CreateContract(objectType);
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
// If object type is a subclass of MyDynamicObject and the property is declared
// in a subclass of MyDynamicObject, assume it is marked with JsonProperty
// (unless it is explicitly ignored). By checking IsSubclassOf we ensure that
// "bookkeeping" properties like Count, Keys and Values are not serialized.
if (type.IsSubclassOf(typeof(MyDynamicObject)) && memberSerialization == MemberSerialization.OptOut)
{
foreach (var property in properties)
{
if (!property.Ignored && property.DeclaringType.IsSubclassOf(typeof(MyDynamicObject)))
{
property.HasMemberAttribute = true;
}
}
}
return properties;
}
}
Then, to use the contract resolver, cache it somewhere for performance:
static IContractResolver resolver = new MyContractResolver();
And then do:
var settings = new JsonSerializerSettings
{
ContractResolver = resolver,
};
string json = JsonConvert.SerializeObject(obj, settings);
Sample fiddle here.
I can't tell what is inside of ProxyInfo class. However, when using a string for both Name and Proxy property, deserialization works correctly. Please check the following working sample:
class Program
{
static void Main(string[] args)
{
// NOTE: This is how I load the JSON data into the new type.
var obj = JsonConvert.DeserializeObject<MyCustomDynamicObject>("{name:'name1', proxy:'string'}");
var proxy = obj.Proxy;
var name = obj.Name;
}
}
public class MyDynamicObject : DynamicObject
{
// Implements the functionality to store dynamic properties in
// dictionary.
// NOTE: This base class does not have any declared properties.
}
// NOTE: This is the actual concrete type that has declared properties
public class MyCustomDynamicObject : MyDynamicObject
{
public string Name { get; set; }
public string Proxy { get; set; }
}
I have a need to format the output json of a decimal to a currency, with the culture specified my the object I am serializing, the object could be nested so I cannot preset the option in the serializer. The current way I am doing this is by using extra string properties that format the output.
[JsonIgnore]
public decimal Cost {get;set;}
[JsonIgnore]
public CultureInfo Culture {get;set;}
public string AsCurrency(decimal value) {
return string.Format(this.Culture, "{0:c}", value);
}
[JsonProperty("FormattedCost")]
public string FormatedCost {
get { return this.AsCurrency(this.Cost); }
}
I have alot of properties to deal with, I'm not bothered about Deserializing, the JsonObject is used by a different language to populated a PDF and so I want the string values.
Ideally I'd like a JsonConverter so I can just do
[JsonProperty("FormattedCost")]
[JsonConverter(typeof(MyCurrencyConverter))]
public decimal Cost {get;set;}
The issue I have is how to access the Culture property of the containing object in the converter.
public class MyCurrencyConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var culture = // How do I get the Culture from the parent object?
writer.WriteValue(string.format(culture, "{0:c}", (decimal)value);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return typeof(decimal) == objectType;
}
}
As Requested sample JSON.
for an array of Contract classes that each have a Cost and an Culture.
[{ FormattedCost : "£5000.00"}, { FormattedCost : "$8000.00"}, { FormattedCost : "€599.00"}]
The actual objects are a lot more complicated, multiple fields with nested Assets that would have their own figures. Additionally not all decimals would be currencies.
I don't really want to have to write a custom serializer for the Contract itself as I would then have to modify it each time the properties change.
The ideal solution is being able to tag certain decimal properties with the converter attribute so it can handle it.
The other way I was thinking of going was to make a custom class for the decimal properties with an implicit conversion from decimal, however that gets more complicated as some properties are calculated properties based on previous results.
WORKAROUND
I have a work-around for my use case, but it uses reflection to obtain a private variable in the serializer.
var binding = BindingFlags.NonPublic | BindingFlags.Instance;
var writer = serializer.GetType()
.GetMethod("GetInternalSerializer", binding)
?.Invoke(serializer, null);
var parent = writer?.GetType()
.GetField("_serializeStack", binding)
?.GetValue(writer) is List<object> stack
&& stack.Count > 1 ? stack[stack.Count - 2] as MyType: null;
In my tested use cases this gives me the parent object, but it's not using the public API.
What you want to do is to intercept and modify the value of a specific property of an object as it is being serialized while using default serialization for all other properties. This can be done with a custom ContractResolver that replaces the ValueProvider of the property in question when a specific attribute is applied.
First, define the following attribute and contract resolver:
[System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple = false)]
public class JsonFormatAttribute : System.Attribute
{
public JsonFormatAttribute(string formattingString)
{
this.FormattingString = formattingString;
}
/// <summary>
/// The format string to pass to string.Format()
/// </summary>
public string FormattingString { get; set; }
/// <summary>
/// The name of the underlying property that returns the object's culture, or NULL if not applicable.
/// </summary>
public string CulturePropertyName { get; set; }
}
public class FormattedPropertyContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
return base.CreateProperties(type, memberSerialization)
.AddFormatting();
}
}
public static class JsonContractExtensions
{
class FormattedValueProvider : IValueProvider
{
readonly IValueProvider baseProvider;
readonly string formatString;
readonly IValueProvider cultureValueProvider;
public FormattedValueProvider(IValueProvider baseProvider, string formatString, IValueProvider cultureValueProvider)
{
this.baseProvider = baseProvider;
this.formatString = formatString;
this.cultureValueProvider = cultureValueProvider;
}
#region IValueProvider Members
public object GetValue(object target)
{
var value = baseProvider.GetValue(target);
var culture = cultureValueProvider == null ? null : (CultureInfo)cultureValueProvider.GetValue(target);
return string.Format(culture ?? CultureInfo.InvariantCulture, formatString, value);
}
public void SetValue(object target, object value)
{
// This contract resolver should only be used for serialization, not deserialization, so throw an exception.
throw new NotImplementedException();
}
#endregion
}
public static IList<JsonProperty> AddFormatting(this IList<JsonProperty> properties)
{
ILookup<string, JsonProperty> lookup = null;
foreach (var jsonProperty in properties)
{
var attr = (JsonFormatAttribute)jsonProperty.AttributeProvider.GetAttributes(typeof(JsonFormatAttribute), false).SingleOrDefault();
if (attr != null)
{
IValueProvider cultureValueProvider = null;
if (attr.CulturePropertyName != null)
{
if (lookup == null)
lookup = properties.ToLookup(p => p.UnderlyingName);
var cultureProperty = lookup[attr.CulturePropertyName].FirstOrDefault();
if (cultureProperty != null)
cultureValueProvider = cultureProperty.ValueProvider;
}
jsonProperty.ValueProvider = new FormattedValueProvider(jsonProperty.ValueProvider, attr.FormattingString, cultureValueProvider);
jsonProperty.PropertyType = typeof(string);
}
}
return properties;
}
}
Next, define your object as follows:
public class RootObject
{
[JsonFormat("{0:c}", CulturePropertyName = nameof(Culture))]
public decimal Cost { get; set; }
[JsonIgnore]
public CultureInfo Culture { get; set; }
public string SomeValue { get; set; }
public string SomeOtherValue { get; set; }
}
Finally, serialize as follows:
var settings = new JsonSerializerSettings
{
ContractResolver = new FormattedPropertyContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy(),
},
};
var json = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
Notes:
Since you are not serializing the culture name, I can't see any way to deserialize the Cost property. Thus I threw an exception from the SetValue method.
(And, even if you were serializing the culture name, since a JSON object is an unordered set of name/value pairs according the standard, there's no way to guarantee the culture name appears before the cost in the JSON being deserialized. This may be related to why Newtonsoft does not provide access to the parent stack. During deserialization there's no guarantee that required properties in the parent hierarchy have been read - or even that the parents have been constructed.)
If you have to apply several different customization rules to your contracts, consider using ConfigurableContractResolver from How to add metadata to describe which properties are dates in JSON.Net.
You may want to cache the contract resolver for best performance.
Another approach would be to add a converter to the parent object that generates a default serialization to JObject by disabling itself temporarily, tweaks the returned JObject, then writes that out. For examples of this approach see JSON.Net throws StackOverflowException when using [JsonConvert()] or Can I serialize nested properties to my class in one operation with Json.net?.
In comments you write, Inside WriteJson I cannot figure out how to access the parent object and it's properties. It should be possible to do this with a custom IValueProvider that returns a Tuple or similar class containing the parent and the value, which would be used in concert with a specific JsonConverter that expects such input. Not sure I'd recommend this though since it's extremely tricky.
Working sample .Net fiddle.
I'm looking to write a JsonConverter which escapes HTML in strings, unless the [AllowHtml] attribute has been applied;
private class ObjectWithStrings
{
// will be HTML-escaped
public string Name { get; set; }
// won't be escaped
[AllowHtml]
public string Unsafe { get; set; }
}
So I'm trying to write a JsonConverter with a custom ReadJson property;
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var s = (string)reader.Value;
if (s == null)
{
return null;
}
// here I need to get a PropertyInfo so I can call GetCustomAttribute<AllowHtmlAttribute>();
var encoded = System.Web.Security.AntiXss.AntiXssEncoder.HtmlEncode(s, useNamedEntities: true);
return encoded;
}
The gap I've got is that I can't see if Json.Net will let me know the property I'm reading into. Consequently, I can't figure out how to get the property's custom attributes.
Is there a way to find out what property I'm serialising into, or a different pattern recommended for this kind of thing?
EDIT: I failed to write a clear question; I've attempted to write a JsonConverter which deserialises strings, -- see the implementation above of CanConvert(). I suspect that choice is the start of my problem; I may need to deserialise objects with string properties, and do a standard deserialize except when deserialising particular properties.
From within a custom JsonConverter, you can find the name of the JSON property being deserialized by picking it out of the Path property from the JsonReader.
string propertyName = reader.Path.Split('.').Last();
However, this will not solve your overall problem. Assuming the name of the JSON property matches your target class property, you'd still need a way to get the parent object type so you can get the custom attributes from it. Unfortunately, this information is not available to you inside a converter. A converter is intended to be responsible only for the object type it says it can convert (string in your case), and that object's child properties (none in this case, since string is a primitive). So, to make it work, the converter would need to be written to operate on the parent class, and would then need to handle all the string properties of that class. Since your goal seems to be to apply the HTML encoding behavior to all strings in all classes, then you would need a generic converter that handles all non-primitive types, which could get pretty messy, depending on the breadth of what you're trying to deserialize.
Fortunately, there is a better way. Instead of using a JsonConverter, you can use a custom IContractResolver in combination with a IValueProvider to solve this. A ContractResolver is much better suited to problems like this where you want to apply a certain behavior broadly.
Below is an example of the code you would need. The CustomResolver class extends the DefaultContractResolver provided by Json.Net. The CreateProperties() method inspects the JsonProperty objects created by the base resolver and attaches an instance of the inner HtmlEncodingValueProvider class to any string properties which do not have the [AllowHtml] attribute applied. Each value provider later handles the actual encoding of its target string property via the SetValue() method.
public class CustomResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
// Find all string properties that do not have an [AllowHtml] attribute applied
// and attach an HtmlEncodingValueProvider instance to them
foreach (JsonProperty prop in props.Where(p => p.PropertyType == typeof(string)))
{
PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
if (pi != null && pi.GetCustomAttribute(typeof(AllowHtmlAttribute), true) == null)
{
prop.ValueProvider = new HtmlEncodingValueProvider(pi);
}
}
return props;
}
protected class HtmlEncodingValueProvider : IValueProvider
{
PropertyInfo targetProperty;
public HtmlEncodingValueProvider(PropertyInfo targetProperty)
{
this.targetProperty = targetProperty;
}
// SetValue gets called by Json.Net during deserialization.
// The value parameter has the original value read from the JSON;
// target is the object on which to set the value.
public void SetValue(object target, object value)
{
var encoded = System.Web.Security.AntiXss.AntiXssEncoder.HtmlEncode((string)value, useNamedEntities: true);
targetProperty.SetValue(target, encoded);
}
// GetValue is called by Json.Net during serialization.
// The target parameter has the object from which to read the string;
// the return value is the string that gets written to the JSON
public object GetValue(object target)
{
// if you need special handling for serialization, add it here
return targetProperty.GetValue(target);
}
}
}
To use the resolver, create a new JsonSerializerSettings instance, then set its ContractResolver property to a new instance of the custom resolver and pass the settings to the JsonConvert.DeserializeObject() method.
Here is a short demo:
class Program
{
static void Main(string[] args)
{
string json = #"
{
""Name"" : ""<b>Foo Bar</b>"",
""Description"" : ""<p>Bada Boom Bada Bing</p>"",
}";
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new CustomResolver()
};
Foo foo = JsonConvert.DeserializeObject<Foo>(json, settings);
Console.WriteLine("Name: " + foo.Name);
Console.WriteLine("Desc: " + foo.Description);
}
}
class Foo
{
public string Name { get; set; }
[AllowHtml]
public string Description { get; set; }
}
class AllowHtmlAttribute : Attribute { }
Here is the output. Notice that the Name property gets HTML encoded while the Description property does not.
Name: <b>Foo Bar</b>
Desc: <p>Bada Boom Bada Bing</p>
Fiddle: https://dotnetfiddle.net/cAg4NC
I need to be able to control how/whether certain properties on a class are serialized. The simplest case is [ScriptIgnore]. However, I only want these attributes to be honored for this one specific serialization situation I am working on - if other modules downstream in the application also want to serialize these objects, none of these attributes should get in the way.
So my thought is to use a custom attribute MyAttribute on the properties, and initialize the specific instance of JsonSerializer with a hook that knows to look for that attribute.
At first glance, I don't see any of the available hook points in JSON.NET will provide the PropertyInfo for the current property to do such an inspection - only the property's value. Am I missing something? Or a better way to approach this?
Here's a generic reusable "ignore property" resolver based on the accepted answer:
/// <summary>
/// Special JsonConvert resolver that allows you to ignore properties. See https://stackoverflow.com/a/13588192/1037948
/// </summary>
public class IgnorableSerializerContractResolver : DefaultContractResolver {
protected readonly Dictionary<Type, HashSet<string>> Ignores;
public IgnorableSerializerContractResolver() {
this.Ignores = new Dictionary<Type, HashSet<string>>();
}
/// <summary>
/// Explicitly ignore the given property(s) for the given type
/// </summary>
/// <param name="type"></param>
/// <param name="propertyName">one or more properties to ignore. Leave empty to ignore the type entirely.</param>
public void Ignore(Type type, params string[] propertyName) {
// start bucket if DNE
if (!this.Ignores.ContainsKey(type)) this.Ignores[type] = new HashSet<string>();
foreach (var prop in propertyName) {
this.Ignores[type].Add(prop);
}
}
/// <summary>
/// Is the given property for the given type ignored?
/// </summary>
/// <param name="type"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
public bool IsIgnored(Type type, string propertyName) {
if (!this.Ignores.ContainsKey(type)) return false;
// if no properties provided, ignore the type entirely
if (this.Ignores[type].Count == 0) return true;
return this.Ignores[type].Contains(propertyName);
}
/// <summary>
/// The decision logic goes here
/// </summary>
/// <param name="member"></param>
/// <param name="memberSerialization"></param>
/// <returns></returns>
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (this.IsIgnored(property.DeclaringType, property.PropertyName)
// need to check basetype as well for EF -- #per comment by user576838
|| this.IsIgnored(property.DeclaringType.BaseType, property.PropertyName)) {
property.ShouldSerialize = instance => { return false; };
}
return property;
}
}
And usage:
var jsonResolver = new IgnorableSerializerContractResolver();
// ignore single property
jsonResolver.Ignore(typeof(Company), "WebSites");
// ignore single datatype
jsonResolver.Ignore(typeof(System.Data.Objects.DataClasses.EntityObject));
var jsonSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ContractResolver = jsonResolver };
Use the JsonIgnore attribute.
For example, to exclude Id:
public class Person {
[JsonIgnore]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
You have a few options. I recommend you read the Json.Net documentation article on the subject before reading below.
The article presents two methods:
Create a method that returns a bool value based on a naming convention that Json.Net will follow to determine whether or not to serialize the property.
Create a custom contract resolver that ignores the property.
Of the two, I favor the latter. Skip attributes altogether -- only use them to ignore properties across all forms of serialization. Instead, create a custom contract resolver that ignores the property in question, and only use the contract resolver when you want to ignore the property, leaving other users of the class free to serialize the property or not at their own whim.
Edit To avoid link rot, I'm posting the code in question from the article
public class ShouldSerializeContractResolver : DefaultContractResolver
{
public new static readonly ShouldSerializeContractResolver Instance =
new ShouldSerializeContractResolver();
protected override JsonProperty CreateProperty( MemberInfo member,
MemberSerialization memberSerialization )
{
JsonProperty property = base.CreateProperty( member, memberSerialization );
if( property.DeclaringType == typeof(Employee) &&
property.PropertyName == "Manager" )
{
property.ShouldSerialize = instance =>
{
// replace this logic with your own, probably just
// return false;
Employee e = (Employee)instance;
return e.Manager != e;
};
}
return property;
}
}
Here is a method based on drzaus' excellent serializer contract which uses lambda expressions. Simply add it to the same class. After all, who doesn't prefer the compiler to do the checking for them?
public IgnorableSerializerContractResolver Ignore<TModel>(Expression<Func<TModel, object>> selector)
{
MemberExpression body = selector.Body as MemberExpression;
if (body == null)
{
UnaryExpression ubody = (UnaryExpression)selector.Body;
body = ubody.Operand as MemberExpression;
if (body == null)
{
throw new ArgumentException("Could not get property name", "selector");
}
}
string propertyName = body.Member.Name;
this.Ignore(typeof (TModel), propertyName);
return this;
}
You can now ignore properties easily and fluently:
contract.Ignore<Node>(node => node.NextNode)
.Ignore<Node>(node => node.AvailableNodes);
I don't care to set the property names as strings, in case they ever change it would break my other code.
I had several "view modes" on the objects I needed to serialized, so I ended up doing something like this in the contract resolver (view mode provided by constructor argument):
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (viewMode == ViewModeEnum.UnregisteredCustomer && member.GetCustomAttributes(typeof(UnregisteredCustomerAttribute), true).Length == 0)
{
property.ShouldSerialize = instance => { return false; };
}
return property;
}
Where my objects look like this:
public interface IStatement
{
[UnregisteredCustomer]
string PolicyNumber { get; set; }
string PlanCode { get; set; }
PlanStatus PlanStatus { get; set; }
[UnregisteredCustomer]
decimal TotalAmount { get; }
[UnregisteredCustomer]
ICollection<IBalance> Balances { get; }
void SetBalances(IBalance[] balances);
}
The downside to this would be the bit of reflection in the resolver, but I think it's worth it to have more maintainable code.
I had good results with the combination of both drzaus and Steve Rukuts answers. However, I face a problem when I set JsonPropertyAttribute with a different name or caps for the property. For example:
[JsonProperty("username")]
public string Username { get; set; }
Include UnderlyingName into consideration solves the problem:
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (this.IsIgnored(property.DeclaringType, property.PropertyName)
|| this.IsIgnored(property.DeclaringType, property.UnderlyingName)
|| this.IsIgnored(property.DeclaringType.BaseType, property.PropertyName)
|| this.IsIgnored(property.DeclaringType.BaseType, property.UnderlyingName))
{
property.ShouldSerialize = instance => { return false; };
}
return property;
}
If you are willing to use F# (or simply use an API not optimized for C#), the FSharp.JsonSkippable library allows you to control in a simple and strongly typed manner whether to include a given property when serializing (and determine whether a property was included when deserializing), and moreover, to control/determine exclusion separately of nullability. (Full disclosure: I'm the author of the library.)
This would appear to imply "no". Which is unfortunate.
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class,
AllowMultiple = true, Inherited = true)]
public class CustomDescriptionAttribute : Attribute
{
public string Description { get; private set; }
public CustomDescriptionAttribute(string description)
{
Description = description;
}
}
[CustomDescription("IProjectController")]
public interface IProjectController
{
void Create(string projectName);
}
internal class ProjectController : IProjectController
{
public void Create(string projectName)
{
}
}
[TestFixture]
public class CustomDescriptionAttributeTests
{
[Test]
public void ProjectController_ShouldHaveCustomDescriptionAttribute()
{
Type type = typeof(ProjectController);
object[] attributes = type.GetCustomAttributes(
typeof(CustomDescriptionAttribute),
true);
// NUnit.Framework.AssertionException: Expected: 1 But was: 0
Assert.AreEqual(1, attributes.Length);
}
}
Can a class inherit attributes from an interface? Or am I barking up the wrong tree here?
No. Whenever implementing an interface or overriding members in a derived class, you need to re-declare the attributes.
If you only care about ComponentModel (not direct reflection), there is a way ([AttributeProvider]) of suggesting attributes from an existing type (to avoid duplication), but it is only valid for property and indexer usage.
As an example:
using System;
using System.ComponentModel;
class Foo {
[AttributeProvider(typeof(IListSource))]
public object Bar { get; set; }
static void Main() {
var bar = TypeDescriptor.GetProperties(typeof(Foo))["Bar"];
foreach (Attribute attrib in bar.Attributes) {
Console.WriteLine(attrib);
}
}
}
outputs:
System.SerializableAttribute
System.ComponentModel.AttributeProviderAttribute
System.ComponentModel.EditorAttribute
System.Runtime.InteropServices.ComVisibleAttribute
System.Runtime.InteropServices.ClassInterfaceAttribute
System.ComponentModel.TypeConverterAttribute
System.ComponentModel.MergablePropertyAttribute
You can define a useful extension method ...
Type type = typeof(ProjectController);
var attributes = type.GetCustomAttributes<CustomDescriptionAttribute>( true );
Here is the extension method:
/// <summary>Searches and returns attributes. The inheritance chain is not used to find the attributes.</summary>
/// <typeparam name="T">The type of attribute to search for.</typeparam>
/// <param name="type">The type which is searched for the attributes.</param>
/// <returns>Returns all attributes.</returns>
public static T[] GetCustomAttributes<T>( this Type type ) where T : Attribute
{
return GetCustomAttributes( type, typeof( T ), false ).Select( arg => (T)arg ).ToArray();
}
/// <summary>Searches and returns attributes.</summary>
/// <typeparam name="T">The type of attribute to search for.</typeparam>
/// <param name="type">The type which is searched for the attributes.</param>
/// <param name="inherit">Specifies whether to search this member's inheritance chain to find the attributes. Interfaces will be searched, too.</param>
/// <returns>Returns all attributes.</returns>
public static T[] GetCustomAttributes<T>( this Type type, bool inherit ) where T : Attribute
{
return GetCustomAttributes( type, typeof( T ), inherit ).Select( arg => (T)arg ).ToArray();
}
/// <summary>Private helper for searching attributes.</summary>
/// <param name="type">The type which is searched for the attribute.</param>
/// <param name="attributeType">The type of attribute to search for.</param>
/// <param name="inherit">Specifies whether to search this member's inheritance chain to find the attribute. Interfaces will be searched, too.</param>
/// <returns>An array that contains all the custom attributes, or an array with zero elements if no attributes are defined.</returns>
private static object[] GetCustomAttributes( Type type, Type attributeType, bool inherit )
{
if( !inherit )
{
return type.GetCustomAttributes( attributeType, false );
}
var attributeCollection = new Collection<object>();
var baseType = type;
do
{
baseType.GetCustomAttributes( attributeType, true ).Apply( attributeCollection.Add );
baseType = baseType.BaseType;
}
while( baseType != null );
foreach( var interfaceType in type.GetInterfaces() )
{
GetCustomAttributes( interfaceType, attributeType, true ).Apply( attributeCollection.Add );
}
var attributeArray = new object[attributeCollection.Count];
attributeCollection.CopyTo( attributeArray, 0 );
return attributeArray;
}
/// <summary>Applies a function to every element of the list.</summary>
private static void Apply<T>( this IEnumerable<T> enumerable, Action<T> function )
{
foreach( var item in enumerable )
{
function.Invoke( item );
}
}
Update:
Here is a shorter version as proposed by SimonD in a comment:
private static IEnumerable<T> GetCustomAttributesIncludingBaseInterfaces<T>(this Type type)
{
var attributeType = typeof(T);
return type.GetCustomAttributes(attributeType, true)
.Union(type.GetInterfaces().SelectMany(interfaceType =>
interfaceType.GetCustomAttributes(attributeType, true)))
.Cast<T>();
}
An article by Brad Wilson about this: Interface Attributes != Class Attributes
To summarise: classes don't inherit from interfaces, they implement them. This means that the attributes are not automatically part of the implementation.
If you need to inherit attributes, use an abstract base class, rather than an interface.
While a C# class does not inherit attributes from its interfaces, there is a useful alternative when binding models in ASP.NET MVC3.
If you declare the view's model to be the interface rather than the concrete type, then the view and the model binder will apply the attributes (e.g., [Required] or [DisplayName("Foo")] from the interface when rendering and validating the model:
public interface IModel {
[Required]
[DisplayName("Foo Bar")]
string FooBar { get; set; }
}
public class Model : IModel {
public string FooBar { get; set; }
}
Then in the view:
#* Note use of interface type for the view model *#
#model IModel
#* This control will receive the attributes from the interface *#
#Html.EditorFor(m => m.FooBar)
This is more for people looking to extract attributes from properties that may exist on an implemented interface. Because those attributes are not part of the class, this will give you access to them. note, I have a simple container class that gives you access to the PropertyInfo - as that is what I needed it for. Hack up as you need. This worked well for me.
public static class CustomAttributeExtractorExtensions
{
/// <summary>
/// Extraction of property attributes as well as attributes on implemented interfaces.
/// This will walk up recursive to collect any interface attribute as well as their parent interfaces.
/// </summary>
/// <typeparam name="TAttributeType"></typeparam>
/// <param name="typeToReflect"></param>
/// <returns></returns>
public static List<PropertyAttributeContainer<TAttributeType>> GetPropertyAttributesFromType<TAttributeType>(this Type typeToReflect)
where TAttributeType : Attribute
{
var list = new List<PropertyAttributeContainer<TAttributeType>>();
// Loop over the direct property members
var properties = typeToReflect.GetProperties();
foreach (var propertyInfo in properties)
{
// Get the attributes as well as from the inherited classes (true)
var attributes = propertyInfo.GetCustomAttributes<TAttributeType>(true).ToList();
if (!attributes.Any()) continue;
list.AddRange(attributes.Select(attr => new PropertyAttributeContainer<TAttributeType>(attr, propertyInfo)));
}
// Look at the type interface declarations and extract from that type.
var interfaces = typeToReflect.GetInterfaces();
foreach (var #interface in interfaces)
{
list.AddRange(#interface.GetPropertyAttributesFromType<TAttributeType>());
}
return list;
}
/// <summary>
/// Simple container for the Property and Attribute used. Handy if you want refrence to the original property.
/// </summary>
/// <typeparam name="TAttributeType"></typeparam>
public class PropertyAttributeContainer<TAttributeType>
{
internal PropertyAttributeContainer(TAttributeType attribute, PropertyInfo property)
{
Property = property;
Attribute = attribute;
}
public PropertyInfo Property { get; private set; }
public TAttributeType Attribute { get; private set; }
}
}
One of the answers worked for attributes placed on the interface itself, but I was looking for interface property member attributes. I could not find it anywhere and had to alter some of the answers here to get what I needed. Going to leave the extension method I used here. This method will get all custom attributes of type T from a PropertyInfo including attributes placed on interfaces.
public static IEnumerable<T> GetAllCustomAttributes<T> (this MemberInfo member) where T: Attribute
{
return member.GetCustomAttributes<T>(true)
.Union(member.DeclaringType.GetInterfaces().SelectMany(i => i.GetProperties())
.Select(p => p.GetCustomAttribute<T>(true)));
}
For my case I have a lot of cards and each card can have a two icons, but those icons refer to different values. All the values were being defined on my interfaces and I didn't want to bring each down to the class implementation since it would be the same across all cards. My usage looks like:
public interface IConsumable
{
[CardIcon(CardIconPosition.Right)]
public int Food { get; }
}
public class FoodCard : IConsumable
{
public bool TryGetCardIcon(CardIconPosition cardIconPosition, out string text)
{
var property = Card.GetType().GetProperties()
.FirstOrDefault(p => p.GetAllCustomAttributes<CardIconAttribute>()?
.Any(c => c.CardIconPosition == cardIconPosition) ?? false);
bool hasProperty = property != null;
text = string.Empty;
if (hasProperty)
{
text = property?.GetValue(Card).ToString() ?? string.Empty;
}
return hasProperty;
}
}
EDIT: this covers inheriting attributes from interfaces on members (incl. properties). There are simple answers above for type definitions. I just posted this because I found it to be an irritating limitation and wanted to share a solution :)
Interfaces are multiple inheritance and behave as inheritance in the type system. There isn't a good reason for this kind of stuff. Reflection is a bit hokey. I've added comments to explain the nonsense.
(This is .NET 3.5 because this it just happens to be what the project I'm doing at the moment is using.)
// in later .NETs, you can cache reflection extensions using a static generic class and
// a ConcurrentDictionary. E.g.
//public static class Attributes<T> where T : Attribute
//{
// private static readonly ConcurrentDictionary<MemberInfo, IReadOnlyCollection<T>> _cache =
// new ConcurrentDictionary<MemberInfo, IReadOnlyCollection<T>>();
//
// public static IReadOnlyCollection<T> Get(MemberInfo member)
// {
// return _cache.GetOrAdd(member, GetImpl, Enumerable.Empty<T>().ToArray());
// }
// //GetImpl as per code below except that recursive steps re-enter via the cache
//}
public static List<T> GetAttributes<T>(this MemberInfo member) where T : Attribute
{
// determine whether to inherit based on the AttributeUsage
// you could add a bool parameter if you like but I think it defeats the purpose of the usage
var usage = typeof(T).GetCustomAttributes(typeof(AttributeUsageAttribute), true)
.Cast<AttributeUsageAttribute>()
.FirstOrDefault();
var inherit = usage != null && usage.Inherited;
return (
inherit
? GetAttributesRecurse<T>(member)
: member.GetCustomAttributes(typeof (T), false).Cast<T>()
)
.Distinct() // interfaces mean duplicates are a thing
// note: attribute equivalence needs to be overridden. The default is not great.
.ToList();
}
private static IEnumerable<T> GetAttributesRecurse<T>(MemberInfo member) where T : Attribute
{
// must use Attribute.GetCustomAttribute rather than MemberInfo.GetCustomAttribute as the latter
// won't retrieve inherited attributes from base *classes*
foreach (T attribute in Attribute.GetCustomAttributes(member, typeof (T), true))
yield return attribute;
// The most reliable target in the interface map is the property get method.
// If you have set-only properties, you'll need to handle that case. I generally just ignore that
// case because it doesn't make sense to me.
PropertyInfo property;
var target = (property = member as PropertyInfo) != null ? property.GetGetMethod() : member;
foreach (var #interface in member.DeclaringType.GetInterfaces())
{
// The interface map is two aligned arrays; TargetMethods and InterfaceMethods.
var map = member.DeclaringType.GetInterfaceMap(#interface);
var memberIndex = Array.IndexOf(map.TargetMethods, target); // see target above
if (memberIndex < 0) continue;
// To recurse, we still need to hit the property on the parent interface.
// Why don't we just use the get method from the start? Because GetCustomAttributes won't work.
var interfaceMethod = property != null
// name of property get method is get_<property name>
// so name of parent property is substring(4) of that - this is reliable IME
? #interface.GetProperty(map.InterfaceMethods[memberIndex].Name.Substring(4))
: (MemberInfo) map.InterfaceMethods[memberIndex];
// Continuation is the word to google if you don't understand this
foreach (var attribute in interfaceMethod.GetAttributes<T>())
yield return attribute;
}
}
Barebones NUnit test
[TestFixture]
public class GetAttributesTest
{
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
private sealed class A : Attribute
{
// default equality for Attributes is apparently semantic
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
private sealed class ANotInherited : Attribute { }
public interface Top
{
[A, ANotInherited]
void M();
[A, ANotInherited]
int P { get; }
}
public interface Middle : Top { }
private abstract class Base
{
[A, ANotInherited]
public abstract void M();
[A, ANotInherited]
public abstract int P { get; }
}
private class Bottom : Base, Middle
{
[A, ANotInherited]
public override void M()
{
throw new NotImplementedException();
}
[A, ANotInherited]
public override int P { get { return 42; } }
}
[Test]
public void GetsAllInheritedAttributesOnMethods()
{
var attributes = typeof (Bottom).GetMethod("M").GetAttributes<A>();
attributes.Should()
.HaveCount(3, "there are 3 inherited copies in the class heirarchy and A is inherited");
}
[Test]
public void DoesntGetNonInheritedAttributesOnMethods()
{
var attributes = typeof (Bottom).GetMethod("M").GetAttributes<ANotInherited>();
attributes.Should()
.HaveCount(1, "it shouldn't get copies of the attribute from base classes for a non-inherited attribute");
}
[Test]
public void GetsAllInheritedAttributesOnProperties()
{
var attributes = typeof(Bottom).GetProperty("P").GetAttributes<A>();
attributes.Should()
.HaveCount(3, "there are 3 inherited copies in the class heirarchy and A is inherited");
}
[Test]
public void DoesntGetNonInheritedAttributesOnProperties()
{
var attributes = typeof(Bottom).GetProperty("P").GetAttributes<ANotInherited>();
attributes.Should()
.HaveCount(1, "it shouldn't get copies of the attribute from base classes for a non-inherited attribute");
}
}
Add interface with properties that have attributes/custom attributes attached to the same properties that class have. We can extract the interface of the class by using Visual studio refactor feature.
Have a partial class implement that interface.
Now Get "Type" object of the class object and get custom attributes from the property info using getProperties on Type object.
This will not give the custom attributes on the class object as the class properties did not had the interface properties' custom attributes attached/inherited.
Now call GetInterface(NameOfImplemetedInterfaceByclass) on the class's Type object retrieved above. This will
provide the interface's "Type" object. we should know the implemented interface's NAME. From Type object get property information and if the interface's property has any custom attributes attached then property information will provide
custom attribute list. The implementing class must have provided implementation of the interface's properties.
Match the class object's specific property name within the list of the interface's property information to get the custom attributes list.
This will work.
Though my answer is late and specific to a certain case, I would like to add some ideas.
As suggested in other answers, Reflection or other methods would do it.
In my case a property (timestamp) was needed in all models to meet certain requirement (concurrency check attribute) in a Entity framework core project.
We could either add [] above all class properties (adding in IModel interface which models implemented, didn't work). But I saved time through Fluent API which is helpful in these cases. In fluent API, I can check for specific property name in all models and set as IsConcurrencyToken() in 1 line !!
var props = from e in modelBuilder.Model.GetEntityTypes()
from p in e.GetProperties()
select p;
props.Where(p => p.PropertyInfo.Name == "ModifiedTime").ToList().ForEach(p => { p.IsConcurrencyToken = true; });
Likewise if you need any attribute to be added to same property name in 100's of classes/models, we can use fluent api methods for inbuilt or custom attribute resolver.
Though EF (both core and EF6) fluent api may use reflection behind the scenes, we can save effort :)