Как отфильтровать поля с пользовательским атрибутом в asp.net Web API? - PullRequest
3 голосов
/ 21 марта 2019

У меня есть рабочая модель, которую я использую в своем приложении. Я хочу предоставить некоторые из этих данных через общедоступный API, но у меня есть поля, которые я не хочу возвращать для общего потребления. Один из трудоемких способов сделать это состоит в том, чтобы создать отдельную модель и использовать автоматическое использование, чтобы отобразить мой вывод для создания некоторой серии DTO.

Что я хотел бы сделать, так это аннотировать мою модель с помощью пользовательского атрибута, а затем каким-то образом иметь какой-либо метод расширения или фильтр действий web-API, отфильтровывать аннотированные поля во время выполнения перед отправкой JSON клиенту. Я не могу использовать JsonIgnore, потому что мне нужны эти поля для операций в моем приложении.

Может кто-нибудь дать мне обзор того, как я это сделаю?

заранее спасибо

Редактировать

Так что я думаю, что могу использовать свойство newtonsoft ShouldSerialize, однако затрудняюсь найти элегантный способ задания условия, вызывающего это. У меня сложная модель, и я подумал бы, что во время выполнения мне нужно будет отразить весь вывод, обнаружить любой класс в определенном пространстве имен и установить какое-то значение, которое заставит ShouldSerialize возвращать true

1 Ответ

1 голос
/ 21 марта 2019

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

Сначала создайте пользовательский атрибут, чтобы отметить свойства вашей модели, которые не должны отображаться.через ваш общедоступный API:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
class DontSendInPublicApiAttribute : Attribute { }

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

public static void RemoveSecretData(object obj)
{
    // Retrieve all public instance properties defined for the object's type and marked with [DontSendInPublicApi]
    var propertiesToHide = obj.GetType()
        .GetProperties(BindingFlags.Instance | BindingFlags.Public)
        .Where(p => p.GetCustomAttribute<DontSendInPublicApiAttribute>() != null);

    foreach (var prop in propertiesToHide)
    {
        // Set all of these properties in the given object to their default values.
        // VALUE TYPES (ints, chars, doubles, etc.) will be set to default(TheTypeOfValue), by calling Activator.CreateInstance(TheTypeOfValue).
        // REFERENCE TYPES will simply be set to null.
        var propertyType = prop.PropertyType;
        if (propertyType.IsValueType)
            prop.SetValue(obj, Activator.CreateInstance(prop.PropertyType));
        else
            prop.SetValue(obj, null);
    }
}

Тогдапримените атрибут к любым полям в вашей модели, которые вы хотите скрыть:

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    [DontSendInPublicApi]
    public string Occupation { get; set; }
    [DontSendInPublicApi]
    public int Salary { get; set; }
}

И вот пример того, как его вызвать:

var person = new Person() { Name = "John", Age = 29, Occupation = "Engineer", Salary = 200000 };
RemoveSecretData(person);

После того, как RemoveSecretData(person) был выполнену вас будут свойства Occupation и Salary объекта person, равные null и 0, соответственно.

Примечания об этом решении:

  • Работает только на свойствах.При необходимости вам придется изменить метод RemoveSecretData(), чтобы он также работал с полями.
  • Не рекурсивно обращается к графу объектов.Если ваш объект ссылается на другой объект с некоторым свойством, помеченным [DontSendInPublicApi], это свойство не будет скрыто.Вам придется изменить метод RemoveSecretData() для выполнения рекурсивных вызовов более глубоких объектов, если это необходимо.Следите за циклическими ссылками, если вы планируете это сделать.
  • Скрытые свойства все равно будут отображаться в выходном файле JSON, но свойства со значением всегда будут иметь значение 0 (ноль).) и свойства с типом ссылки всегда будут иметь значение null.
...