JSON ContractResolver создается при каждом выпуске запроса - PullRequest
0 голосов
/ 19 октября 2018

У меня есть приложение .NET Core Web Api 2.1, в котором я сериализую только свойства, запрошенные клиентом.

Пример: GET orders/1?select=Id,TotalAmount

Пример: GET orders/1?select=Id,CustomerName,DeliveryAddress,Location,ZipCode

Для этого приложение создает объект в каждом запросе (Lifetime Scoped) для получения запрошенных свойств.

Затем я создал пользовательский класс ContractResolver, который создается в каждом запросе глобальным IResultFilter:

public class SerializationFilter : IResultFilter
{
    private readonly IApiQueryParameters _apiQueryParameters;

    public SerializationFilter(IApiQueryParameters apiQueryParameters)
    {
        this._apiQueryParameters = apiQueryParameters;
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var objectResult = context.Result as ObjectResult;

        if (objectResult != null)
        {
            var contractResolver = new SelectiveResourceContractResolver(this._apiQueryParameters);
            var serializerSettings = new JsonSerializerSettings
            {
                ContractResolver = contractResolver
            };

            var jsonFormatter = new JsonOutputFormatter(
                serializerSettings,
                ArrayPool<char>.Shared);

            objectResult.Formatters.Add(jsonFormatter);
        }
    }
}

Теперь это работает для первого запроса, сделанного после подключения приложения к сети.,Второй запрос создает ContractResolver правильно, но ответ не является правильным.Возвращенные сериализованные свойства не являются запрошенными клиентом.

Отладка кода, я заметил, что когда создается SelectiveResourceContractResolver, он обращается к методу конструктора вправо,

    public SelectiveResourceContractResolver(IApiQueryParameters apiQueryParameters)
    {
        this._apiQueryParameters = apiQueryParameters;            
    }

Также,он запускает метод переопределения CreateProperty:

 protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)

Но во втором запросе CreatePropertyMethod не запускается.

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        property.ShouldSerialize =
            instance =>
            {
                ...
            };

        return property;
    }

Во второй раз, он просто выполняет property.ShouldSerialize = instance => часть.Я думаю, что какое-то кэширование выполняется приложением, но более странным является то, что ContractResolver создается при каждом запросе (он не устанавливается глобально в Startup.cs) при выполнении фильтра.Кроме того, когда я отлаживаю его во втором запросе, свойство IApiQueryParameters в ContractResolver имеет все значения первого запроса, а не второго выполнения конструктора.

Чего мне здесь не хватает?

1 Ответ

0 голосов
/ 25 апреля 2019

Я предполагаю, что ваш SelectiveResourceContractResolver наследуется от DefaultContractResolver.

DefaultContractResolver.ResolveContract, который вызывается внутренне при сериализации, кэширует контракты в статическом поточно-ориентированном словаре , поэтому CreateContract (что, в свою очередь, вызывает CreateProperty) будет вызываться только один раз для каждого типа, пока выполняется процесс WebAPI.

Это потому, что вызов CreateContract стоит дорого, а не кэширует контрактысерьезно повлияет на производительность сериализации.

Если вам нужно только кэшировать контракты для каждого ответа, вы можете создать собственный кэш экземпляра в SelectiveResourceContractResolver и переопределить ResolveContract, чтобы использовать вместо этого кеш:

public class InstanceCachingContractResolver : DefaultContractResolver
{
    private readonly Dictionary<Type, JsonContract> contractCache = new Dictionary<Type, JsonContract>();

    public override JsonContract ResolveContract(Type type)
    {
        if (!contractCache.TryGetValue(type, out JsonContract contract))
        {
            contract = CreateContract(type);
            contractCache.Add(type, contract);
        }
        return contract;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...