Фильтрация свойств в API ASP.NET Core

Я хочу использовать в своем API следующий JSON:

{
  "id": 1
  "name": "Muhammad Rehan Saeed",
  "phone": "123456789",
  "address": {
    "address": "Main Street",
    "postCode": "AB1 2CD"
  }
}

Я хочу дать клиенту возможность отфильтровывать свойства, которые им не интересны. Чтобы следующий URL-адрес возвращал подмножество JSON:

`/api/contact/1?include=name,address.postcode

{
  "name": "Muhammad Rehan Saeed",
  "address": {
    "postCode": "AB1 2CD"
  }
}

Как лучше всего реализовать эту функцию в ASP.NET Core, чтобы:

  1. Решение может применяться глобально, к одному контроллеру или действию, например к фильтру.
  2. Если решение использует отражение, то также должен быть способ оптимизировать конкретное действие контроллера, предоставив ему некоторый код для ручной фильтрации свойств по соображениям производительности.
  3. Он должен поддерживать JSON, но было бы неплохо поддерживать другие форматы сериализации, такие как XML.

Я нашел это решение, в котором используется настраиваемый JSON.Net ContractResolver. Сопоставитель контрактов можно применить глобально, добавив его к сопоставителю контрактов по умолчанию, используемому ASP.Net Core, или вручную к одному действию, например этот код, но не для контроллера. Кроме того, это реализация, специфичная для JSON.


person Muhammad Rehan Saeed    schedule 02.04.2016    source источник
comment
Это надежная ссылка, та, что я опубликовал, делает что-то похожее. Вопрос в том, как лучше всего использовать эти методы расширения в ASP.NET Core? Кроме того, это решение решает проблему с JSON, но как насчет XML?   -  person Muhammad Rehan Saeed    schedule 02.04.2016
comment
Эта запись в блоге была для меня очень полезной. Как ограничить сериализованные свойства с помощью Json.NET и Web API 2.0 с помощью настраиваемого ContractResolver   -  person tsu1980    schedule 27.07.2016
comment
Вам следует начать рассматривать GraphQL для этой необходимости.   -  person olivier houssin    schedule 26.04.2019


Ответы (1)


Вы можете использовать dynamic с ExpandoObject для создания динамического объекта, содержащего необходимые вам свойства. ExpandoObject - это то, что ключевое слово dynamic используется под капотом, что позволяет динамически добавлять и удалять свойства / методы во время выполнения.

[HttpGet("test")]
public IActionResult Test()
{
    dynamic person = new System.Dynamic.ExpandoObject();

    var personDictionary = (IDictionary<string, object>)person;
    personDictionary.Add("Name", "Muhammad Rehan Saeed");

    dynamic address = new System.Dynamic.ExpandoObject();
    var addressDictionary = (IDictionary<string, object>)address;
    addressDictionary.Add("PostCode", "AB1 2CD");

    personDictionary.Add("Address", address);

    return Json(person);
}

Это приводит к

{"Name":"Muhammad Rehan Saeed","Address":{"PostCode":"AB1 2CD"}}

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

person Tseng    schedule 02.04.2016
comment
Как показано в вашем примере, свойства из динамического класса сериализуются в PascalCasing (или как есть), тогда как свойства из обычного класса по умолчанию сериализуются в camelCasing в .NET Core. Есть идеи, как сделать динамические свойства camelCasing? - person Niels Brinch; 26.12.2016
comment
@NielsBrinch: Извините, не видел ранее комментарий, но dynamic под капотом просто использует ExpandoObject, который является IDictionary<string,object>, поэтому при его сериализации вы эффективно сериализуете словарь в объект JSON - person Tseng; 10.06.2017