WebAPI:JSON ReferenceHandler.Preserve
WebAPI : JSON ReferenceHandler.Preserve
我正在使用 Blazor(托管)并希望在将结果发送回客户端时保留引用。下面的示例并不真正需要引用保存,但它是我针对需要的更复杂结构的测试场景。
- Class“员工”在共享项目中定义。
- WebAPI 方法return一个 IEnumerable
有效负载如下所示:
[
{
"id":"a583baf9-8990-484f-9dc6-e8ea822f49c6",
"name":"Neil",
"themeName":"Blue Gray"
},
{
"id":"a7a8e753-c7af-4b29-9242-7b2f5bdac830",
"name":"Caroline",
"themeName":"Yellow"
}
]
正在使用
var result = await response.Content.ReadFromJsonAsync<IEnumerable<Staff>>();
我可以在客户端中获取我的 Staff 对象。
继续参考保存:
我在服务器上更新了 StartUp.cs 以包括:
services.AddControllersWithViews()
.AddJsonOptions(o =>
o.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve
);
结果是 return 有效载荷现在看起来像这样:
{
"$id":"1",
"$values":
[
{
"$id":"2",
"id":"a583baf9-8990-484f-9dc6-e8ea822f49c6",
"name":"Neil",
"themeName":"Blue Gray"
},
{
"$id":"3",
"id":"a7a8e753-c7af-4b29-9242-7b2f5bdac830",
"name":"Caroline",
"themeName":"Yellow"
}
]
}
似乎正确。
这导致了 JSON 行的反序列化异常:
var result = await response.Content.ReadFromJsonAsync<IEnumerable<Staff>>();
所以,我认为在客户端反序列化时我可能也需要包含引用处理选项。所以,改为:
JsonSerializerOptions options = new JsonSerializerOptions();
options.ReferenceHandler = ReferenceHandler.Preserve;
var result = await response.Content.ReadFromJsonAsync<IEnumerable<Staff>>(options);
我没有收到任何错误,但我的 Enumerable 包括:
2 个 Staff 对象(但会将所有属性置为空)。
Enumerable 中的第三个空对象。
谁能指导我做错了什么?
我找到了解决办法。这似乎是正在发生的事情:
WebAPI 上 Json 序列化的默认配置似乎是驼峰式大小写。然而,即使是这种情况,我在客户端序列化共享 类(使用大写)和反序列化时也没有任何问题,即使 JSON 本身使用驼峰大小写。
当我将 ReferenceHandler.Preserve 添加到我的 JsonSerializerOptions 时,这开始失败。
更新我的 Json 选项如下,解决了问题:
services.AddControlersWithViews()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
options.JsonSerializerOptions.PropertyNamingPolicy = null // prevent camel case
}
替代方法是使用 MvcOptions。我不知道哪个更好,但上面和下面的结果似乎相同。
services.AddControllersWithViews(options =>
{
options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
options.OutputFormatters.Add(new SystemTextJsonOutputFormatter(
new JsonSerializerOptions(JsonSerializerDefaults.Web)
{
ReferenceHandler = ReferenaceHandler.Preserve,
PropertyNamingPolicy = null // prevent camel casing of Json
}));
});
然后在 客户端 上,当收到来自 WebAPI 的响应时:
HttpResponseMessage response = await Http.GetAsync(myapiroute);
IEnumerable<Staff> staff = response.Content.ReadFromJsonAsync<IEnumerable<Staff>>(
new JsonSerializerOptions() { ReferenceHandler = ReferenceHandler.Preserve });
现在引用处理似乎跨越了从 WebAPI 到 Blazor 客户端的边界。
我正在使用 Blazor(托管)并希望在将结果发送回客户端时保留引用。下面的示例并不真正需要引用保存,但它是我针对需要的更复杂结构的测试场景。
- Class“员工”在共享项目中定义。
- WebAPI 方法return一个 IEnumerable
有效负载如下所示:
[
{
"id":"a583baf9-8990-484f-9dc6-e8ea822f49c6",
"name":"Neil",
"themeName":"Blue Gray"
},
{
"id":"a7a8e753-c7af-4b29-9242-7b2f5bdac830",
"name":"Caroline",
"themeName":"Yellow"
}
]
正在使用
var result = await response.Content.ReadFromJsonAsync<IEnumerable<Staff>>();
我可以在客户端中获取我的 Staff 对象。
继续参考保存:
我在服务器上更新了 StartUp.cs 以包括:
services.AddControllersWithViews()
.AddJsonOptions(o =>
o.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve
);
结果是 return 有效载荷现在看起来像这样:
{
"$id":"1",
"$values":
[
{
"$id":"2",
"id":"a583baf9-8990-484f-9dc6-e8ea822f49c6",
"name":"Neil",
"themeName":"Blue Gray"
},
{
"$id":"3",
"id":"a7a8e753-c7af-4b29-9242-7b2f5bdac830",
"name":"Caroline",
"themeName":"Yellow"
}
]
}
似乎正确。
这导致了 JSON 行的反序列化异常:
var result = await response.Content.ReadFromJsonAsync<IEnumerable<Staff>>();
所以,我认为在客户端反序列化时我可能也需要包含引用处理选项。所以,改为:
JsonSerializerOptions options = new JsonSerializerOptions();
options.ReferenceHandler = ReferenceHandler.Preserve;
var result = await response.Content.ReadFromJsonAsync<IEnumerable<Staff>>(options);
我没有收到任何错误,但我的 Enumerable 包括:
2 个 Staff 对象(但会将所有属性置为空)。 Enumerable 中的第三个空对象。
谁能指导我做错了什么?
我找到了解决办法。这似乎是正在发生的事情:
WebAPI 上 Json 序列化的默认配置似乎是驼峰式大小写。然而,即使是这种情况,我在客户端序列化共享 类(使用大写)和反序列化时也没有任何问题,即使 JSON 本身使用驼峰大小写。
当我将 ReferenceHandler.Preserve 添加到我的 JsonSerializerOptions 时,这开始失败。
更新我的 Json 选项如下,解决了问题:
services.AddControlersWithViews()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
options.JsonSerializerOptions.PropertyNamingPolicy = null // prevent camel case
}
替代方法是使用 MvcOptions。我不知道哪个更好,但上面和下面的结果似乎相同。
services.AddControllersWithViews(options =>
{
options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
options.OutputFormatters.Add(new SystemTextJsonOutputFormatter(
new JsonSerializerOptions(JsonSerializerDefaults.Web)
{
ReferenceHandler = ReferenaceHandler.Preserve,
PropertyNamingPolicy = null // prevent camel casing of Json
}));
});
然后在 客户端 上,当收到来自 WebAPI 的响应时:
HttpResponseMessage response = await Http.GetAsync(myapiroute);
IEnumerable<Staff> staff = response.Content.ReadFromJsonAsync<IEnumerable<Staff>>(
new JsonSerializerOptions() { ReferenceHandler = ReferenceHandler.Preserve });
现在引用处理似乎跨越了从 WebAPI 到 Blazor 客户端的边界。