我有一个.NET Core Web Api 2.1应用程序,在该应用程序中,我仅序列化了客户端请求的属性。
示例:GET orders/1?select=Id,TotalAmount
示例:GET orders/1?select=Id,CustomerName,DeliveryAddress,Location,ZipCode
为此,该应用会在每个请求(生命周期范围)中创建一个对象,以获取请求的属性。
然后,我创建了自定义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中全局设置)。另外,当我在第二个请求中调试它时,ContractResolver中的IApiQueryParameters属性具有第一个请求的所有值,而不是构造函数的第二次执行的所有值。
我在这里想念什么?
答案 0 :(得分:0)
我假设您的SelectiveResourceContractResolver
继承自DefaultContractResolver
。
DefaultContractResolver.ResolveContract
,它在序列化期间在内部被here调用,因此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;
}
}