Есть ли способ получить имя ключа в значении файла JSON

#c# #json #entity-framework #json.net

#c# #json #entity-framework #json.net

Вопрос:

Я хочу заполнить свойство на основе имени имени ключа. Например. Типом адреса для физического адреса будет PhysicalAddress. В настоящее время я использую Newtonsoft.Json. Эта информация будет сохранена в базе данных с использованием EntityFramework.

Спасибо

Это примерная часть файла JSON:

 "person": [
  {
    "physicalAddress": [
      {
        "address": "123 Street Name",
        "postCode": 1122
      }
    ],
    "postalAddress": [
      {
        "address": "123 Street Name",
        "postCode": 1122
      }
    ],
    "registeredAddress": [
      {
        "address": "123 Street Name",
        "postCode": 1122
      }
    ]
  }
  

Это примерная часть класса:

     [JsonProperty("address")]
    public string Address { get; set; }

    [JsonProperty("postCode")]
    public string PostCode { get; set; }

    public string AddressType { get; set; }
  

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

1. Вам понадобится пользовательский код сериализации (например, a JsonConverter )

2. Возможно, создать PhysicalAddress класс, который имеет свойство только для чтения AddressType (и то же самое для postalAddress etc)? Каждый из этих классов может наследоваться от абстрактного класса с абстрактным свойством только для чтения AddressType .

3. Физический адрес в вашем JSON действительно предназначен как массив или как объект? Потому что в вашем примере это похоже на массив. Но я задаю этот вопрос, чтобы я, мы могли определить, что правильно делать для достижения вашей цели.

Ответ №1:

Предполагая, что вы не хотите или не можете изменять клиентскую часть, одним из возможных подходов является создание модели запроса, которая соответствует формату тела запроса, т.Е.

   [JsonProperty("physicalAddress")]
  public List<AddressRequestModel> PhysicalAddress { get; set; }

  [JsonProperty("postalAddress")]
  public List<AddressRequestModel> PostalAddress{ get; set; }

  [JsonProperty("registeredAddress")]
  public List<AddressRequestModel> RegisteredAddress{ get; set; }
  

Где AddressRequestModel будет класс, содержащий свойства Address и PostCode . Затем, когда запрос получен, сопоставьте модель запроса с моделью, необходимой вашему приложению. В mapper вы можете назначить соответствующий тип адреса, т.Е.

 
public class AddressMapper
{
   public List<AddressRequestModel> Map(RequestModel model)
   {
      var addresses = new List<AddressRequestModel>();
      model.PhysicalAddress.ForEach(address => addresses.Add(Map(address, "physicalAddress"));
      model.PostalAddress.ForEach(address => addresses.Add(Map(address, "postalAddress"));
      model.RegisteredAddress.ForEach(address => addresses.Add(Map(address, "registeredAddress"));
      return addresses;
   }

   private AddressRequestModel Map(AddressRequestModel model, string addressType) =>
   new AddressRequestModel
   {
       Address = model.Address,
       PostCode = model.PostCode,
       AddressType = addressType,
   }
}
  

Ответ №2:

Я создаю немного сложный случай для анализа этого json с помощью JsonConverter. И это работает для ваших требований.

Основная функция используется JProperty для динамического получения имени ключа адреса (PhysicalAddress, PostalAddress или другого) и Children() для получения вспомогательных узлов.

 class Program
{

    static void Main(string[] args)
    {
         string json = @"
{""person"": [
  {
    ""physicalAddress"": [
      {
        ""address"": ""123 Street Name"",
        ""postCode"": 1122
      },
      {
        ""address"": ""456 Street Name"",
        ""postCode"": 7788
      }
    ],
    ""postalAddress"": [
      {
        ""address"": ""123 Street Name"",
        ""postCode"": 1122
      },
      {
        ""address"": ""9999 Street Name"",
        ""postCode"": 77886666
      }
    ],
    ""registeredAddress"": [
      {
        ""address"": ""123 Street Name"",
        ""postCode"": 1122
      },
      {
        ""address"": ""fwerg Street Name"",
        ""postCode"": 9999999
      }

    ]
  }
  
  ]
}
";

         Person person = JsonConvert.DeserializeObject<Person>(json, new MyTypeConverter());
     }
}

public class Person
{
    public List<AddressDetail> Addresses { get; set; }
}

public class AddressDetail
{
    public string Address { get; set; }

    public string PostCode { get; set; }

    public string AddressType { get; set; }
}

public class MyTypeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(Person).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartObject)
        {
            JObject item = JObject.Load(reader);
            if (item["person"] != null)
            {
                var pseron = new Person()
                {
                    Addresses = new List<AddressDetail>()
                };
                var largeAddressArr = item["person"].Children();
                foreach (var largeAddress in largeAddressArr)
                {
                    foreach (var keyAddress in largeAddress.Children())
                    {
                        string keyName = (keyAddress as JProperty).Name;
                        List<JToken> tokens = keyAddress.Children().ToList();
                        foreach (var address in tokens)
                        {
                            var addresses = address.ToObject<List<AddressDetail>>();
                            addresses.ForEach(x => x.AddressType = keyName);
                            pseron.Addresses.AddRange(addresses);
                        }
                    }
                }

                return pseron;
            }
        }
        return null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}