WebAPI:JSON引用处理程序,保留

wkftcu5l  于 2022-12-15  发布在  其他
关注(0)|答案(2)|浏览(132)

我正在使用Blazor(托管),并希望在将结果发送回客户端时保留引用。下面的示例实际上并不需要引用保留,但我的测试场景是针对一个更复杂的结构。

  • 类“Staff”是在共享项目中定义的。
  • WebAPI方法返回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
    );

结果是返回的有效负载现在看起来像这样:

{
  "$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中的第三个空对象。
有人能告诉我我做错了什么吗?

rkue9o1l

rkue9o1l1#

我找到了一个解决办法。这是看起来正在发生的事情:
WebAPI上JSON序列化的默认配置似乎是camel大小写,然而,即使是这样,我在序列化共享类(使用大写)和在客户机上反序列化时也没有遇到任何问题,即使JSON本身使用的是camel大小写。
当我将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 Client的界限。

zbsbpyhn

zbsbpyhn2#

在我的例子中,我只有一个控制器导致了这个问题。如果我在program.cs中更改了应用程序范围内的序列化选项,它会导致应用程序的其他部分无法工作。因此,我通过更改以下内容在我的麻烦控制器上重新解决了这个问题(这是一个简化的示例):

return Json(new { status = true });

...到...

var serialized = System.Text.Json.JsonSerializer.Serialize(new { status = true });
return Ok(serialized);

相关问题