Class attribute for snake case properties [duplicate] - c#

I am trying to bind my PascalCased c# model from snake_cased JSON in WebApi v2 (full framework, not dot net core).
Here's my api:
public class MyApi : ApiController
{
[HttpPost]
public IHttpActionResult DoSomething([FromBody]InputObjectDTO inputObject)
{
database.InsertData(inputObject.FullName, inputObject.TotalPrice)
return Ok();
}
}
And here's my input object:
public class InputObjectDTO
{
public string FullName { get; set; }
public int TotalPrice { get; set; }
...
}
The problem that I have is that the JSON looks like this:
{
"full_name": "John Smith",
"total_price": "20.00"
}
I am aware that I can use the JsonProperty attribute:
public class InputObjectDTO
{
[JsonProperty(PropertyName = "full_name")]
public string FullName { get; set; }
[JsonProperty(PropertyName = "total_price")]
public int TotalPrice { get; set; }
}
However my InputObjectDTO is huge, and there are many others like it too. It has hundreds of properties that are all snake cased, and it would be nice to not have to specify the JsonProperty attribute for each property. Can I make it to work "automatically"? Perhaps with a custom model binder or a custom json converter?

No need to reinvent the wheel. Json.Net already has a SnakeCaseNamingStrategy class to do exactly what you want. You just need to set it as the NamingStrategy on the DefaultContractResolver via settings.
Add this line to the Register method in your WebApiConfig class:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() };
Here is a demo (console app) to prove the concept: https://dotnetfiddle.net/v5siz7
If you want to apply the snake casing to some classes but not others, you can do this by applying a [JsonObject] attribute specifying the naming strategy like so:
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
public class InputObjectDTO
{
public string FullName { get; set; }
public decimal TotalPrice { get; set; }
}
The naming strategy set via attribute takes precedence over the naming strategy set via the resolver, so you can set your default strategy in the resolver and then use attributes to override it where needed. (There are three naming strategies included with Json.Net: SnakeCaseNamingStrategy, CamelCaseNamingStrategy and DefaultNamingStrategy.)
Now, if you want to deserialize using one naming strategy and serialize using a different strategy for the same class(es), then neither of the above solutions will work for you, because the naming strategies will be applied in both directions in Web API. So in in that case, you will need something custom like what is shown in #icepickle's answer to control when each is applied.

Well, you should be able to do it using a custom JsonConverter to read your data. Using the deserialization provided in Manojs' answer, you could create a DefaultContractResolver that would create a custom deserialization when the class has a SnakeCasedAttribute specified above.
The ContractResolver would look like the following
public class SnakeCaseContractResolver : DefaultContractResolver {
public new static readonly SnakeCaseContractResolver Instance = new SnakeCaseContractResolver();
protected override JsonContract CreateContract(Type objectType) {
JsonContract contract = base.CreateContract(objectType);
if (objectType?.GetCustomAttributes(true).OfType<SnakeCasedAttribute>().Any() == true) {
contract.Converter = new SnakeCaseConverter();
}
return contract;
}
}
The SnakeCaseConverter would be something like this?
public class SnakeCaseConverter : JsonConverter {
public override bool CanConvert(Type objectType) => objectType.GetCustomAttributes(true).OfType<SnakeCasedAttribute>().Any() == true;
private static string ConvertFromSnakeCase(string snakeCased) {
return string.Join("", snakeCased.Split('_').Select(part => part.Substring(0, 1).ToUpper() + part.Substring(1)));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
var target = Activator.CreateInstance( objectType );
var jobject = JObject.Load(reader);
foreach (var property in jobject.Properties()) {
var propName = ConvertFromSnakeCase(property.Name);
var prop = objectType.GetProperty(propName);
if (prop == null || !prop.CanWrite) {
continue;
}
prop.SetValue(target, property.Value.ToObject(prop.PropertyType, serializer));
}
return target;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
throw new NotImplementedException();
}
}
And then you could annotate your dto class using this attribute (which is just a placeholder)
[SnakeCased]
public class InputObjectDTO {
public string FullName { get; set; }
public int TotalPrice { get; set; }
}
and for reference, this is the used attribute
[AttributeUsage(AttributeTargets.Class)]
public class SnakeCasedAttribute : Attribute {
public SnakeCasedAttribute() {
// intended blank
}
}
One more thing to notice is that in your current form the JSON converter would throw an error ("20.00" is not an int), but I am going to guess that from here you can handle that part yourself :)
And for a complete reference, you could see the working version in this dotnetfiddle

You can add cusrom json converter code like below. This should allow you to specify property mapping.
public class ApiErrorConverter : JsonConverter
{
private readonly Dictionary<string, string> _propertyMappings = new Dictionary<string, string>
{
{"name", "error"},
{"code", "errorCode"},
{"description", "message"}
};
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return objectType.GetTypeInfo().IsClass;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object instance = Activator.CreateInstance(objectType);
var props = objectType.GetTypeInfo().DeclaredProperties.ToList();
JObject jo = JObject.Load(reader);
foreach (JProperty jp in jo.Properties())
{
if (!_propertyMappings.TryGetValue(jp.Name, out var name))
name = jp.Name;
PropertyInfo prop = props.FirstOrDefault(pi =>
pi.CanWrite && pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);
prop?.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
}
return instance;
}
}
Then specify this attribute on your class.
This should work.
This blog explains the approach using console Application. https://www.jerriepelser.com/blog/deserialize-different-json-object-same-class/

Related

C# reflection - get object value from property value within JSON ContractResolver

I have a class PersonDto which contains a property instance of type AddressDto. I am building a custom ContractResolver named eg. ShouldSerializeContractResolver with Newtonsoft.Json marshalling .NET lib that will include only specific properties into serialization that are marked with my custom attribute eg. [ShouldSerialize]
The problem occurs when the CreateProperty method of the resolver goes into the complex / custom type of the PersonDto ie. it goes into the AddressDto and it is not aware that the property instance is tagged with the [ShouldSerialize] attribute. The resulting serialization then looks like "Address": {} instead of "Address": { "StreetNumber": 123 }
The code looks like:
class AddressDto
{
// PROBLEM 1/2: value does not get serialized, but I want it serialized as its property is [ShouldSerialize] attr tagged
public int StreetNumber { get; set; }
}
class PersonDto
{
public string Name { get; set; } // should not serialize as has not attr on it
[ShouldSerialize]
public string Id { get; set; }
[ShouldSerialize]
public AddressDto Address { get; set; }
}
// JSON contract resolver:
public class ShouldSerializeContractResolver: DefaultContractResolver
{
public ShouldSerializeContractResolver() { }
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
var attr = member.GetCustomAttribute<ShouldSerializeContractResolver>(inherit: false);
// PROBLEM 2/2: here I need the code to access the member.DeclaringType instance somehow and then
// find its AddressDto property and its GetCustomAttribute<ShouldSerializeContractResolver>
if (attr is null)
{
property.ShouldSerialize = instance => { return false; };
}
return property;
}
}
// code invoked as:
PersonDto somePerson = IrrelevantSomePersonCreateNewFactoryFn();
var jsonSettings = new JsonSerializerSettings { ContractResolver = new ShouldSerializeContractResolver() };
var strJson = JsonConvert.SerializeObject(somePerson, jsonSettings);
The serializer works in a "flat" mode, ie. it runs through all the props with the resolver and it comes to the point where the member is StreetNumber and from it I do not know how to access the "parent" MemberInfo, which would be great.
What I find as the core issue here is I do not have the "parent" / DeclaringType object instance and need to find a way on how to obtain it.
Please note that I can not solve this issue through [JsonProperty], [JsonIgnore] etc. as my attribute is complex and involves its own logic.
You would like AddressDto to be serialized differently depending upon whether it was encountered via a property marked with [ShouldSerialize], however that cannot easily be done using a custom contract resolver because Json.NET creates exactly one contract for each type no matter where it is encountered in the serialization graph. I.e. a contract resolver will generate the same contract for AddressDto for both of the following data models:
class PersonDto
{
public string Name { get; set; } // should not serialize as has not attr on it
[ShouldSerialize]
public string Id { get; set; }
[ShouldSerialize]
public AddressDto Address { get; set; } // This and its properties should get serialized.
}
class SomeOtherDto
{
[ShouldSerialize]
public string SomeOtherValue { get; set; }
public AddressDto SecretAddress { get; set; } // Should not get serialized.
}
This is why you cannot get the referring property's attributes when creating the properties for a referenced type.
Instead, you will need to track in runtime when the serializer begins and ends serialization of a [ShouldSerialize] property, setting some thread-safe state variable while inside. This can be done e.g. by using your contract resolver to inject a custom JsonConverter that sets the necessary state, disables itself temporarily to prevent recursive calls, then does a default serialization:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class ShouldSerializeAttribute : System.Attribute
{
}
public class ShouldSerializeContractResolver: DefaultContractResolver
{
static ThreadLocal<bool> inShouldSerialize = new (() => false);
static bool InShouldSerialize { get => inShouldSerialize.Value; set => inShouldSerialize.Value = value; }
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
var attr = member.GetCustomAttribute<ShouldSerializeAttribute>(inherit: false);
if (attr is null)
{
var old = property.ShouldSerialize;
property.ShouldSerialize = instance => InShouldSerialize && (old == null || old(instance));
}
else
{
var old = property.Converter;
if (old == null)
property.Converter = new InShouldSerializeConverter();
else
property.Converter = new InShouldSerializeConverterDecorator(old);
}
return property;
}
class InShouldSerializeConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var old = InShouldSerialize;
try
{
InShouldSerialize = true;
serializer.Serialize(writer, value);
}
finally
{
InShouldSerialize = old;
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
public override bool CanRead => false;
public override bool CanConvert(Type objectType) => throw new NotImplementedException();
}
class InShouldSerializeConverterDecorator : JsonConverter
{
readonly JsonConverter innerConverter;
public InShouldSerializeConverterDecorator(JsonConverter innerConverter) => this.innerConverter = innerConverter ?? throw new ArgumentNullException(nameof(innerConverter));
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var old = InShouldSerialize;
try
{
InShouldSerialize = true;
if (innerConverter.CanWrite)
innerConverter.WriteJson(writer, value, serializer);
else
serializer.Serialize(writer, value);
}
finally
{
InShouldSerialize = old;
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var old = InShouldSerialize;
try
{
InShouldSerialize = true;
if (innerConverter.CanRead)
return innerConverter.ReadJson(reader, objectType, existingValue, serializer);
else
return serializer.Deserialize(reader, objectType);
}
finally
{
InShouldSerialize = old;
}
}
public override bool CanConvert(Type objectType) => throw new NotImplementedException();
}
}
Then serialize as follows:
IContractResolver resolver = new ShouldSerializeContractResolver(); // Cache statically & reuse for best performance
var settings = new JsonSerializerSettings
{
ContractResolver = resolver,
};
var json = JsonConvert.SerializeObject(person, Formatting.Indented, settings);
Notes:
Newtonsoft recommends caching and reusing your contract resolver for best performance.
The above implementation has the limitation that, if your [ShouldSerialize] is also marked with JsonPropertyAttribute, fields that control serialization of the property value such as ItemConverterType and IsReference will be ignored.
Demo fiddle here.

Conditionally change the types of certain properties when serializing to JSON

I have a custom class, which I am serializing using JSON.NET.
In that class, lets call it posInvoice, I have properties such as UnitPrice, Quantity, and TotalAmount which are of type string. This works fine when I send the serialized object to an endpoint as a POST Request.
Now I have another endpoint, which accepts the same class, posInvoice. However, this endpoint is expecting these values to be decimals instead.
What would be the best way to handle this in my code? Should I just create another class and change the property types? I have researched and tried to look for a similar situation in Stack Overflow, but couldn't find anything.
Here's the approach I would take:
Define your PosInvoice class using decimals, since that is the most appropriate data type for the amounts.
Create a custom JsonConverter class which can be used during serialization to convert the decimals to strings.
Use the converter with the endpoint which requires the amounts as strings; omit it otherwise.
Model class:
public class PosInvoice
{
public string Description { get; set; }
public decimal UnitPrice { get; set; }
public decimal Quantity { get; set; }
public decimal TotalAmount { get; set; }
}
Converter:
public class InvoiceAmountsAsStringsConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(PosInvoice);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
PosInvoice invoice = (PosInvoice)value;
JsonObjectContract contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(typeof(PosInvoice));
writer.WriteStartObject();
foreach (JsonProperty prop in contract.Properties)
{
writer.WritePropertyName(prop.PropertyName);
object propValue = prop.ValueProvider.GetValue(invoice);
if (propValue is decimal)
{
writer.WriteValue(((decimal)propValue).ToString(CultureInfo.InvariantCulture));
}
else
{
serializer.Serialize(writer, propValue);
}
}
writer.WriteEndObject();
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Usage:
public static string SerializeInvoice(PosInvoice invoice, bool serializeDecimalsAsStrings)
{
var settings = new JsonSerializerSettings { Formatting = Formatting.Indented };
if (serializeDecimalsAsStrings)
{
settings.Converters.Add(new InvoiceAmountsAsStringsConverter());
}
return JsonConvert.SerializeObject(invoice, settings);
}
Working demo here: https://dotnetfiddle.net/4beAW3

How to Omit Inherited Property From JSON.NET Serialization

If I have the following classes I want to serialize using JSON.NET:
[DataContract]
public class Thing
{
[DataMember(Name = "#context")]
public string Context => "http://schema.org"
}
[DataContract]
public class Organization : Thing
{
[DataMember(Name = "address")]
public Address Address { get; set; }
...
}
[DataContract]
public class Address : Thing
{
...
}
When I use JSON.NET to serialize an Organization I get:
{
"#context": "http://schema.org",
"address": {
"#context": "http://schema.org",
...
}
...
}
What is the most efficient way of ensuring that the #context property only appears in the top level Organization object and not in the Address object?
If Organization is the only top level descendant of Thing and also no fields of type Organization may appear in serialized objects, you may easily do this by defining ShouldSerializeContext in Thing as follows:
[DataContract]
public class Thing
{
[DataMember(Name = "#context")]
public string Context => "http://schema.org";
public bool ShouldSerializeContext() { return this is Organization; }
}
Demo: https://dotnetfiddle.net/GjmfbA
If any of the Thing's descendants may act as the root object, you may need to implement a custom converter. In WriteJson method of this converter, you may filter properties to be serialized. To remove the Context property from all but the root object check writer.Path, which will be an empty string for the root object:
[DataContract]
[JsonConverter(typeof(NoContextConverter))]
public class Thing
{
[DataMember(Name = "#context")]
public string Context => "http://schema.org";
}
// ...............
public class NoContextConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var props = value.GetType().GetProperties()
.Where(p => Attribute.IsDefined(p, typeof(DataMemberAttribute)))
.ToList();
if (writer.Path != "")
props.RemoveAll(p => p.Name == "Context");
writer.WriteStartObject();
foreach (var prop in props)
{
writer.WritePropertyName(prop.GetCustomAttribute<DataMemberAttribute>().Name);
serializer.Serialize(writer, prop.GetValue(value, null));
}
writer.WriteEndObject();
}
public override bool CanConvert(Type objectType)
{
return typeof(Thing).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Demo: https://dotnetfiddle.net/cIlXID
N.B. For some reason, dotnetfiddle.net does not allow to use DataContractAttribute and DataMemberAttribute from System.Runtime.Serialization so I had to comment out relevant lines in this demo.
While #DimitryEgorov's answer is probably the correct way to go, it uses reflection which makes it slow. In the solution below, I use StringBuilder to do a string replace on the final JSON.
private const string ContextPropertyJson = "\"#context\":\"http://schema.org\",";
public override string ToString() => RemoveAllButFirstContext(
JsonConvert.SerializeObject(this, new JsonSerializerSettings));
private static string RemoveAllButFirstContext(string json)
{
var stringBuilder = new StringBuilder(json);
var startIndex = ContextPropertyJson.Length + 1;
stringBuilder.Replace(
ContextPropertyJson,
string.Empty,
startIndex,
stringBuilder.Length - startIndex - 1);
return stringBuilder.ToString();
}

How to handle conversion from string to enum when string starts with a number in Json.Net

I am receiving json from a server which I am converting to an object using Json.Net. For one member I am using the StringEnumConverter which works really perfect.
However all of a sudden the server decided to use strings which also can start with a number which results in a JsonSerilizationException - obviously because enums cannot start with a number in .Net.
Now I am trying to find a solution to handle that.My first approach was to add a "_" when Reading the Json (so my enums in the code would have a starting _ when they are followed by a number) and when writing the json I would delete the starting _ (if a number is following). To achieve this I copied the StringEnumConverter into my namespace and tried to change the according part in the WriteJson and ReadJson methods. However I cannot use the StringEnumConverter since there are other dependencies I cannot access in my own namespace.
Is there any elegant solution to this problem?
You can create a JsonConverter and trim the digits from the front
public class Json_34159840
{
public static string JsonStr = #"{""enum"":""1Value"",""name"":""James"",""enum2"":""1""}";
public static void ParseJson()
{
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new EnumConverter() }
};
// Later on...
var result = JsonConvert.DeserializeObject<JsonClass>(JsonStr);
Console.WriteLine(result.Enum);
Console.WriteLine(result.Enum2);
Console.WriteLine(result.Name);
}
}
public class EnumConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var str = value.ToString();
if (Regex.IsMatch(str, #"^_"))
{
writer.WriteValue(str.Substring(1));
}
else
{
writer.WriteValue(str);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var value = reader.Value.ToString();
if (Regex.IsMatch(value, #"^\d+$"))
{
return Enum.Parse(objectType, value);
}
if (Regex.IsMatch(value, #"^\d+"))
{
value = "_" + value;
}
return Enum.Parse(objectType, value);
}
public override bool CanConvert(Type objectType)
{
//You might want to do a more specific check like
//return objectType == typeof(JsonEnum);
return objectType.IsEnum;
}
}
public enum JsonEnum
{
_0Default,
_1Value
}
public class JsonClass
{
public string Name { get; set; }
public JsonEnum Enum { get; set; }
public JsonEnum Enum2 { get; set; }
}
Hope this helps.
EDIT: Added support for integers :D
A simple strategy is to deserialize the value into a string property and then convert into your own data type (enum or otherwise) via an accessor method or a secondary getter-only property.

Serialize poco containing object property into Json

I have a class that I need to serialize to pass to another system.
The class contains a property that is defined as an object, because the type of class the object will contain can vary at runtime.
My classes looks something like this simplified mock up;
public class MyTestXML
{
public string String1 { get; set; }
public string String2 { get; set; }
[System.Xml.Serialization.XmlElementAttribute("First", typeof(MyFirstObject),
Form = System.Xml.Schema.XmlSchemaForm.Qualified)]
[System.Xml.Serialization.XmlElementAttribute("Second", typeof(MySecondObject),
Form = System.Xml.Schema.XmlSchemaForm.Qualified)]
public object MyObject { get; set; }
}
public class MyFirstObject
{
public string theFirstObjectString { get; set; }
}
public class MySecondObject
{
public string theSecondObjectString { get; set; }
}
This class serializes perfectly to xml by using the XmlElementAttribute and XmlSerializer, but when I try and serialize it to Json (using Newtonsoft Json.Net), the object is of an undefined type, and it cannot be deserialized.
Is there a way to specify the XmlElementAttribute in Json attributes to achieve the same result when serialized?
I would like to offer the use of Json for the serialised object, as it is half the size of the xml, but cannot unless I can solve the serialization of the object property issue.
Thanks in advance.
You would have to create your own custom serialization behaviour. Have a look at this answer here : https://stackoverflow.com/a/22722467/2039359 on how to implement your own JsonConverter for Json.Net
In your case you could do something like this to create your json
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
MyTestXML myTestXml = (MyTestXML) value;
JObject jObject = JObject.FromObject(value);
JProperty prop = jObject.Children<JProperty>().First(p=>p.Name.Contains("MyObject"));
if (myTestXml.MyObject.GetType() == typeof (MyFirstObject))
{
prop.AddAfterSelf(new JProperty("First", JToken.FromObject(myTestXml.MyObject)));
prop.Remove();
jObject.WriteTo(writer);
}
else if (myTestXml.MyObject.GetType() == typeof (MySecondObject))
{
prop.AddAfterSelf(new JProperty("Second", JToken.FromObject(myTestXml.MyObject)));
prop.Remove();
jObject.WriteTo(writer);
}
}
And something like this when you are deserializing
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
MyTestXML myTestXml = new MyTestXML();
serializer.Populate(jo.CreateReader(), myTestXml);
object myObject = null;
if (jo["First"] != null)
{
myObject = new MyFirstObject { TheFirstObjectString = jo["First"].SelectToken(#"TheFirstObjectString").Value<string>() };
}
if (jo["Second"] != null)
{
myObject = new MySecondObject { TheSecondObjectString = jo["Second"].SelectToken(#"TheSecondObjectString").Value<string>() };
}
myTestXml.MyObject = myObject;
return myTestXml;
}
To use it you would supply your JsonConverter when serializing/deserializing like so:
var settings = new JsonSerializerSettings();
settings.Converters.Add(new MyTextXmlJsonConverter());
var a = JsonConvert.SerializeObject(myTestXml, settings);
Hope that's what you're looking for
Another alternative is to create a custom contract resolver which would allow you to detect which xml attribute is applied. You can then apply a custom JsonConverter on the property if you needed a specific output.
public class CustomContractResolver : DefaultContractResolver
{
private readonly JsonMediaTypeFormatter formatter;
public CustomContractResolver(JsonMediaTypeFormatter formatter)
{
this.formatter = formatter;
}
public JsonMediaTypeFormatter Formatter
{
[DebuggerStepThrough]
get { return this.formatter; }
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
this.ConfigureProperty(member, property);
return property;
}
private void ConfigureProperty(MemberInfo member, JsonProperty property)
{
if (Attribute.IsDefined(member, typeof(XmlElementAttribute), true))
{
var attribute = member.CustomAttributes.Where(x => x.AttributeType == typeof(XmlElementAttribute)).First();
// do something with your attribute here like apply a converter
property.Converter = new XmlAttributeJsonConverter();
}
}
}

Categories