Я хотел бы создать пользовательский объект Json из классов C # POCO, структура объекта Json будет получена из пользовательских атрибутов, применяемых к классам, ниже приведен пример того, чего я пытаюсь достичь.
Ниже приведено несколько примеров классов
public class SomeBaseClass
{
public int BaseId { get; set; }
public string SomeBaseProperty { get; set; }
}
public class NestedClass
{
public string SomeNestedProp1 { get; set; }
public string SomeNestedProp2 { get; set; }
}
[ModelType(TargetModule.COMPLAINT, ModelAffinity.PARENT)]
public class ChildOne : SomeBaseClass
{
public ChildOne()
{
NestedClasses = new List<NestedClass>();
nestedClassesAgain = new List<NestedClass>();
}
public string SomeProperty { get; set; }
public string SomeProperty1 { get; set; }
public string SomeProperty2 { get; set; }
[ModelType(TargetModule.COMPLAINT, ModelAffinity.NESTED)]
public IList<NestedClass> NestedClasses { get; set; }
public IList<NestedClass> nestedClassesAgain { get; set; }
}
Ниже приведен пример пользовательского атрибута, который используется выше.
[Serializable]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
public sealed class ModelType : Attribute
{
public ModelType(TargetModule targetModule, ModelAffinity modelAffinity)
{
TargetModuleName = targetModule;
ModelAffinityType = modelAffinity;
}
public TargetModule TargetModuleName { get; }
public ModelAffinity ModelAffinityType { get; }
}
public enum TargetModule
{
COMPLAINT,
PAYMENT,
RECEIPTS
}
public enum ModelAffinity
{
PARENT,
NESTED,
}
Ниже приведен объект Json, который я планирую создать с помощью пользовательских атрибутов.
{
"complaint": {
"someproperty": "sample value",
"someproperty1": "sample value1",
"someproperty2": "sample value2",
"baseid": "123",
"somebaseproperty": "sample value3"
"nested": [{
"somenestedprop1": "sample nested value1",
"somenestedprop2": "sample nested value2"
}
],
"nestedclassesagain": [{
"somenestedprop1": "sample nested again value1",
"somenestedprop2": "sample nested again value2"
}]
}
}
В приведенном выше выводе свойства / классы, содержащие пользовательский атрибут, преобразуются в их значения, т.е. свойство «NestedClasses» преобразуется в значение атрибута «nested», если другое свойство «NestedClassesAgain» содержало тот же атрибут, то значения / свойства будут объединены в «вложенный» объект Json Array.
что-то вроде ниже
"nested": [{
"somenestedprop1": "sample nested value1",
"somenestedprop2": "sample nested value2"
},
{
"somenestedprop1": "sample nested again value1",
"somenestedprop2": "sample nested again value2"
}
]
Попытка достижения этого с помощью пользовательского ContractResolver, как показано ниже
public class AttributeContractResolver : DefaultContractResolver
{
private readonly Dictionary<string, string> configDerivedList;
public AttributeContractResolver()
{
configDerivedList = new Dictionary<string, string>
{
{ "ChildOne", "BaseId,SomeProperty,SomeProperty1,NestedClasses,nestedClassesAgain" },
{ "ChildTwo", "BaseId,SomeBaseProperty,SomeOtherProperty1,SomeOtherProperty2" },
{ "NestedClass", "SomeNestedProp1, SomeNestedProp2"},
{ "COMPLAINT", "BaseId,SomeProperty,SomeProperty1,SomeNestedProp1" },
};
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
IEnumerable<(ModelType[] attributes, string propWithAttribute)> tt = (from x in base.GetSerializableMembers(type)
where x.GetCustomAttributes(typeof(ModelType), false).Length > 0
let attributes = (ModelType[])x.GetCustomAttributes(typeof(ModelType), false)
let propWithAttribute = x.Name
select (attributes, propWithAttribute));
var moduleType = (ModelType[])type.GetCustomAttributes(typeof(ModelType), false);
List<string> requiredProperties = (from key in configDerivedList
where moduleType.All(mod => mod
.TargetModuleName
.ToString() == key.Key) &&
tt.All(a => a
.attributes
.All(mod => mod
.TargetModuleName
.ToString() == key.Key))
select key).FirstOrDefault().Value.Split(',').ToList();
requiredProperties.AddRange(from propss in properties
from t in tt
where propss.PropertyName == t.propWithAttribute
select propss.PropertyName);
properties = properties.Where(prop => requiredProperties.Contains(prop.PropertyName, new StringComparer())).ToList();
return properties;
}
}
В приведенном выше примере конвертера я также хотел бы сериализовать свойства на основе значений атрибутов, то есть выборочных свойств на основе атрибутов, установленных в классах.
Надеюсь, я смогу разработать вариант использования.
Заранее спасибо.