Создайте Json с использованием пользовательских атрибутов в c # с помощью newtonsoft json.net

#c# #json #json.net #poco

#c# #json #json.net #poco

Вопрос:

Я хотел бы создать пользовательский объект 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» преобразуется в значение атрибута «вложенный», если другое свойство «NestedClassesAgain» содержит тот же атрибут, тогда значения / свойства будут объединены во «вложенный» объект массива Json.

Что-то вроде приведенного ниже

 "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) amp;amp;
                                                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;
        }
    }

  

В приведенном выше примере конвертера я также хотел бы сериализовать свойства на основе значений атрибутов, т. Е. выборочные свойства на основе атрибутов, установленных в классах.

Надеюсь, я смог бы разработать вариант использования.

Заранее спасибо.

Комментарии:

1. Зачем вообще это делать вместо того, чтобы фактически создавать структуру объекта, которую вы хотите? Работа сериализатора заключается просто в сериализации данных, а не в преобразовании данных из одной формы в другую.

2. Если вы хотите сопоставить типы, вы можете использовать, например, AutoMapper или просто написать код сопоставления. Из-за того, как написан этот вопрос, трудно понять, как выглядят эти две структуры. complaint это имя свойства в JSON, почему оно должно быть указано через атрибут ? Почему бы не использовать анонимный тип, например new {complaint = new WhateverTheRootIs{}} ?

3. Спасибо за ответ, идея состоит в том, чтобы создать структуру на основе атрибутов, примененных к классу, в сценарии реального приложения классы будут определены в клиентском приложении, которое будет иметь доступ к классу пользовательских атрибутов, клиентское приложение будет сериализовать класс и отправлять в очередь, получатель очереди не будет знать структуру класса, который создал json, следовательно, думал о создании структуры json заранее, чтобы получатель не беспокоился об ожидаемой схеме

4. Вы могли бы связать это с применением xslt к xml и преобразованием его в определенную структуру, если это невозможно, есть ли какие-либо другие способы достичь чего-то подобного, основная идея заключается в преобразовании в определенную структуру json в зависимости от предопределенного типа (в этом примере я использовал пользовательский атрибут), любые предложения помогут, еще раз спасибо за ваш ответ

5. Опять же, почему ? То, что вы описываете, — это просто сопоставление. Вы ничего не получите, делая это с помощью жестко закодированных атрибутов. Сопоставления могут быть определены во время выполнения, где атрибуты жестко закодированы во время компиляции. С таким же успехом можно использовать DTO вместо атрибутов. На самом деле, это было бы намного более гибко, чем пытаться заставить модели сущностей работать как DTO