我正在尝试将自定义的iReferenCeresolver实现添加到ASP.NET Core 2.2 MVC API应用程序中,以减少JSON有效负载中的数据。但是,参考分辨率正在不同请求之间共享。
看来,在请求之间共享了参考文献的单个实例。我希望参考可以独立于其他请求解决,因为我的不同用户没有此共享参考上下文。
这是我的ConfigureServices
方法 startup.cs :
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(opts =>
{
opts.SerializerSettings.ReferenceResolverProvider = () => new ThingReferenceResolver();
});
}
这是我的控制器实现,以及我的自定义 ireferenceresolver
[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"
}
]
}
在我的第二个请求中,我得到以下答复:
{
"mainThing": {
"$ref": "foo"
},
"things": [
{
"$ref": "foo"
},
{
"$ref": "bar"
}
]
}
我希望我的第二个请求看起来像我的第一个请求,即可重复的输出。
您会为第二个请求获得不同的结果,因为MVC会创建一个序列化器并缓存它,然后如果您像这样的参考跟踪,则可以缓存引用。
我认为,如果您在每个结果中返回带有新的序列化器设置的JSONRESULT,那么您将不会遇到此问题:
new jsonresult(YourData,new JSonserializertings {...})
我想出的一个选项是绕过配置MVC提供的JSON Serialializer并为所涉及的请求创建我自己的。
[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
);
}
在我的具体情况下,这还可以,因为我没有很多端点需要配置。
这意味着示例 startup.cs is 不需要以下代码解决我的问题(因为我根据请求定义它)
.AddJsonOptions(opts =>
{
opts.SerializerSettings.ReferenceResolverProvider = () => new ThingReferenceResolver();
});
我认为我会为自己的情况解决这个选择,但很想知道是否有更好的方法来实施它。