我试图将自定义IReferenceResolver实现添加到ASP.NET Core 2.2 MVC API应用程序,以减少JSON有效负载中的数据。但是,参考分辨率在不同的请求之间共享。
似乎在请求之间共享ReferenceResolver的单个实例。我希望独立于其他请求来解析引用,因为我的不同用户将没有此共享引用上下文。
这是我在 Startup.cs 中的process_pid=$(ps --no-headers aux | grep "${process_cmd_line}" | grep -v grep | awk '{print $2}' | tr '\n' '')
方法:
ConfigureServices
这是我的控制器实现以及自定义的 IReferenceResolver
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(opts =>
{
opts.SerializerSettings.ReferenceResolverProvider = () => new ThingReferenceResolver();
});
}
我的第一个请求得到以下答复:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet("")]
public ActionResult<ThingsResponse> Get()
{
return new ThingsResponse
{
MainThing = new Thing { Id = "foo" },
Things = new List<Thing>
{
new Thing { Id = "foo" },
new Thing { Id = "bar" }
}
};
}
}
public class ThingsResponse
{
[JsonProperty(IsReference = true)]
public Thing MainThing { get; set; }
[JsonProperty(ItemIsReference = true)]
public List<Thing> Things { get; set; }
}
public class Thing
{
public string Id { get; set; }
}
public class ThingReferenceResolver : IReferenceResolver
{
private readonly IDictionary<string, Thing> _idReference = new Dictionary<string, Thing>();
public void AddReference(object context, string reference, object value)
{
_idReference[reference] = (Thing)value;
}
public string GetReference(object context, object value)
{
var thing = (Thing)value;
_idReference[thing.Id] = thing;
return thing.Id.ToString();
}
public bool IsReferenced(object context, object value)
{
var thing = (Thing)value;
return _idReference.ContainsKey(thing.Id);
}
public object ResolveReference(object context, string reference)
{
_idReference.TryGetValue(reference, out Thing thing);
return thing;
}
}
在我的第二个请求上,我收到以下响应:
{
"mainThing": {
"$id": "foo",
"id": "foo"
},
"things": [
{
"$ref": "foo"
},
{
"$id": "bar",
"id": "bar"
}
]
}
我希望我的第二个请求看起来像我的第一个请求,即可重复的输出。
答案 0 :(得分:1)
对于第二个请求,您将获得不同的结果,因为MVC创建了一个序列化器并对其进行缓存,如果您像这样对引用进行跟踪,则该序列化器将对引用进行缓存。
我认为,如果您在每个结果中返回带有新序列化程序设置的JsonResult,那么您将不会遇到此问题:
new JsonResult(yourData, new JsonSerializerSettings { ... })
答案 1 :(得分:0)
我想出的一个选择是绕过配置MVC提供的JSON序列化程序,并为有问题的请求创建自己的序列化程序。
[HttpGet("")]
public ActionResult<ThingsResponse> Get()
{
var serializerSettings = JsonSerializerSettingsProvider.CreateSerializerSettings();
serializerSettings.ReferenceResolverProvider = () => new ThingReferenceResolver();
return new JsonResult(
new ThingsResponse
{
MainThing = new Thing { Id = "foo" },
Things = new List<Thing>
{
new Thing { Id = "foo" },
new Thing { Id = "bar" }
}
},
serializerSettings
);
}
在我的特定情况下,这是可以的,因为我没有很多端点需要配置。
这意味着不需要示例中的以下代码来解决我的问题(因为我是根据每个请求定义的)
.AddJsonOptions(opts =>
{
opts.SerializerSettings.ReferenceResolverProvider = () => new ThingReferenceResolver();
});
我认为我会根据自己的情况选择此选项,但很想知道是否有更好的方法来实现它。