System.Text.Json 和多态代码:不适用于 WebApi 控制器

2023-12-10

随着 .NET 7.0 的发布,System.Text.Json应该支持多态代码。不幸的是,当您需要从控制器的方法返回派生类型的实例时,它似乎无法开箱即用。例如,假设以下模型:

public class Base {}

public class Derived1: Base  { }

public class Derived2: Base  { }

还假设我们有以下动态类型信息解析器:

public class JsonHierarchyTypeInfoResolver : DefaultJsonTypeInfoResolver {    
    public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) {
        var jsonTypeInfo = base.GetTypeInfo(type, options);

        if( typeof(Base) == jsonTypeInfo.Type ) {
            jsonTypeInfo.PolymorphismOptions = new( ) {
                                                          TypeDiscriminatorPropertyName = "$type", 
                                                          IgnoreUnrecognizedTypeDiscriminators = true,
                                                          UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization,
                                                          DerivedTypes = {
                                                                             new JsonDerivedType(typeof(Derived1), typeof(Derived1).AssemblyQualifiedName!),
                                                                             new JsonDerivedType(typeof(Derived2), typeof(Derived2).AssemblyQualifiedName!)
                                                                         }
                                                      };
            
        }
        return jsonTypeInfo;
    }
}

然后,通过执行以下操作在应用程序中使用它:

builder.Services.AddControllers( )
       .AddJsonOptions(options => {
                           options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
                           options.JsonSerializerOptions.TypeInfoResolver = new JsonHierarchyTypeInfoResolver( );
                       });

我们还假设我们有一个简单的控制器,它有一个简单的方法,如下所示:

[ApiController]
[Route("[controller]")]
public class DEMOController : ControllerBase {
    [HttpGet]
    public ActionResult<Base> GetAsync() {
        var derived = new Derived1(  );
        return Ok(derived);
    }
}

每当调用该方法时,它都不会像我预期的那样生成带有类型鉴别器的 json。看来问题出在SystemTextJsonOutputFormatter当它尝试使用以下代码序列化对象时:

await JsonSerializer.SerializeAsync(responseStream, context.Object, objectType, SerializerOptions, httpContext.RequestAborted);

方法如下objectType已初始化:

// context.ObjectType reflects the declared model type when specified.
// For polymorphic scenarios where the user declares a return type, but returns a derived type,
// we want to serialize all the properties on the derived type. This keeps parity with
// the behavior you get when the user does not declare the return type and with Json.Net at least at the top level.
var objectType = context.Object?.GetType() ?? context.ObjectType ?? typeof(object);

由于该方法使用派生类型,因此自定义信息类型解析器将无法发挥其魔力。我错过了什么吗?这是一个已知的问题?这是否意味着我应该继续使用 json.net 而不是尝试迁移到 System.Text.Json?


ASP.NET Core 解析的类型GetAsync将会Derived1它没有任何多态信息,因此它不会添加任何多态序列化数据。一种解决方案是为层次结构中的每种类型添加多态性信息:

public class JsonHierarchyTypeInfoResolver : DefaultJsonTypeInfoResolver
{
    public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
    {
        var jsonTypeInfo = base.GetTypeInfo(type, options);
        // if type inherits or is Base
        if (jsonTypeInfo.Type.IsAssignableTo(typeof(Base)))
        {
            jsonTypeInfo.PolymorphismOptions = new()
            {
                TypeDiscriminatorPropertyName = "$type",
                IgnoreUnrecognizedTypeDiscriminators = true,
                UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization,
            };

            var derivedTypes = new[]
                {
                    typeof(WeatherForecastController.Derived1),
                    typeof(WeatherForecastController.Derived2)
                }
                .Where(t => jsonTypeInfo.Type.IsAssignableTo(t)) // add only appropriate types
                .Select(t => new JsonDerivedType(t, t.AssemblyQualifiedName!));
            foreach (var derivedType in derivedTypes)
            {
                jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(derivedType);
            }
        }

        return jsonTypeInfo;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

System.Text.Json 和多态代码:不适用于 WebApi 控制器 的相关文章

  • 为什么相同的代码在同一台计算机上的执行时间可能不同?

    我是 C 编程新手 我编写了代码并希望获得它的运行时 这就是我所做的 每次运行代码时 我都会得到不同的运行时值 这样对吗 或者我的代码有问题吗 int main int argc char argv time t start end sta
  • 在 C# 中创建具有单独列的分隔文本

    我一直在尝试在 C 中创建一个制表符限制的文本文件 以便数据正确显示在单独的列中 Firstname Lastname Age John Smith 17 James Sawyer 31 我尝试过 t 字符 但我得到的只是 Firstnam
  • std::cout 和 std::wcout 有什么区别?

    在c 中 有什么区别std cout and std wcout 它们都控制流缓冲区的输出或将内容打印到控制台 或者它们只是相似吗 它们作用于不同的字符类型 std cout uses char作为字符类型 std wcout uses w
  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 将内置类型转换为向量

    我的 TcpClient 类接受vector
  • 如何访问另一个窗体上的ListView控件

    当单击与 ListView 所在表单不同的表单中的按钮时 我试图填充 ListView 我在 Form1 中创建了一个方法以在 Form2 中使用 并将参数传递给 Form1 中的方法 然后填充 ListView 当我调试时 我得到了传递的
  • 存储来自其他程序的事件

    我想将其他应用程序的事件存储在我自己的应用程序中 事件示例 打开 最小化 Word 或打开文件时 这样的事可能吗 运行程序 http msdn microsoft com en us library ms813609 aspx and 打开
  • 在一个字节中存储 4 个不同的值

    我有一个任务要做 但我不知道从哪里开始 我不期待也绝对不想要代码中的答案 我想要一些关于该怎么做的指导 因为我感到有点失落 将变量打包和解包到一个字节中 您需要在一个字节中存储 4 个不同的值 这些值为 NAME RANGE BITS en
  • PlaySound 可在 Visual Studio 中运行,但不能在独立 exe 中运行

    我正在尝试使用 Visual Studio 在 C 中播放 wav 文件 我将文件 my wav 放入项目目录中并使用代码 PlaySound TEXT my wav NULL SND FILENAME SND SYNC 我按下播放按钮 或
  • 将 log4net 与 Autofac 结合使用

    我正在尝试将 log4net 与 Autofac 一起使用 我粘贴了这段代码http autofac readthedocs org en latest examples log4net html http autofac readthed
  • 如何编写一个同时需要请求和响应Dtos的ServiceStack插件

    我需要提供本地化数据服务 所有本地化的响应 Dto 都共享相同的属性 IE 我定义了一个接口 ILocalizedDto 来标记那些 Dto 在请求端 有一个ILocalizedRequest对于需要本地化的请求 Using IPlugin
  • 等待线程完成

    private void button1 Click object sender EventArgs e for int i 0 i lt 15 i Thread nova new Thread Method nova Start list
  • 私有模板函数

    我有一堂课 C h class C private template
  • std::async 与重载函数

    可能的重复 std bind 重载解析 https stackoverflow com questions 4159487 stdbind overload resolution 考虑以下 C 示例 class A public int f
  • 如何对 Web Api 操作进行后调用?

    我创建了一个 Web API 操作 如下所示 HttpPost public void Load string siteName string providerName UserDetails userDetails implementat
  • 线程和 fork()。我该如何处理呢? [复制]

    这个问题在这里已经有答案了 可能的重复 多线程程序中的fork https stackoverflow com questions 1235516 fork in multi threaded program 如果我有一个使用 fork 的
  • memset 未填充数组

    u32 iterations 5 u32 ecx u32 malloc sizeof u32 iterations memset ecx 0xBAADF00D sizeof u32 iterations printf 8X n ecx 0
  • Linq-to-entities,在一个查询中获取结果+行数

    我已经看到了有关此事的多个问题 但它们已经有 2 年 或更长 的历史了 所以我想知道这方面是否有任何变化 基本思想是填充网格视图并创建自定义分页 所以 我还需要结果和行数 在 SQL 中 这将类似于 SELECT COUNT id Id N
  • 检查Windows控制台中是否按下了键[重复]

    这个问题在这里已经有答案了 可能的重复 C 控制台键盘事件 https stackoverflow com questions 2067893 c console keyboard events 我希望 Windows 控制台程序在按下某个
  • 在客户端系统中安装后桌面应用程序无法打开

    我目前正在使用 Visual Studio 2017 和 4 6 1 net 框架 我为桌面应用程序创建了安装文件 安装程序在我的系统中完美安装并运行 问题是安装程序在其他计算机上成功安装 但应用程序无法打开 edit 在客户端系统中下载了

随机推荐

  • D3Js 条形图条形在 X 轴开始后的起始方式

    正如标题所示 我正在使用 D3Js 创建条形图 我必须在以下代码片段中更改哪些内容才能使条形图从 X 轴的开头开始 var allBarsDatasets xAxisTickValue 10 1 barValue 18 xAxisTickV
  • 如何在 Google VR 视图中导航?

    我正在编写一个 Android 应用程序 使用Vr全景视图我知道在 VR 应用程序中有两种导航方式 使用纸板上的单个按钮作为点击 将长时间注视某物视为一次点击 我如何使用其中一个来实现导航 以便如果用户单击按钮 panoview 将跳到下一
  • 多列中每行的最小值(或最大值)

    我正在寻找每行列的最小值 或最大值 的解决方案 喜欢 my data frame is df library tibble df lt tribble name type 1 type 2 type 3 a 1 5 2 b 2 2 6 c
  • 许多组件都不好吗?

    我有一个小问题 在许多软件架构中 例如多层或企业库之类的架构 我在外部程序集中扩展了一些代码 有时 我的项目每个解决方案包含超过 20 个程序集 现在我很困惑 20 个程序集太多了吗 如果是 我可以在具有不同逻辑 部分 的大型项目中做什么
  • Swift:声音输出和麦克风输入 |使用 AudioKit |

    我正在使用 gt Xcode 版本 9 2 lt 我正在使用 gt AudioKit 版本 4 0 4 lt 我已经编写了一些代码 您可以在下面找到它们应该能够 播放特定的声音 frequency 500 0HZ 监听 麦克风输入并实时计算
  • jquery datepicker - 在选择时激活另一个日期选择器

    我有 2 个 jquery 日期选择器来选择日期范围 一旦我选择了起始日期 从第一个日期选择器 我想激活第二个 截止 日期选择器 下面的代码执行此操作 但由于某种原因立即关闭日期选择器 有任何想法吗 http jsfiddle net rN
  • 如何分割长字符串以使其与给定的矩形匹配?

    我有一个长字符串 我想将它分成几部分 以便文本的每一行始终位于给定的矩形中 文本不应超出矩形的边框 矩形的高度不是问题 文本永远不会接触矩形的底部 因为矩形非常高 但这个矩形不是很宽 如何计算每行应该绘制字符串的哪些部分 我不想拆开一个字
  • Arrays.asList().contains() 给出错误的结果

    Code private static final int GOOGLE DIRECTION ID FOR MATCH 11 12 13 14 15 Log e TAG index Arrays asList GOOGLE DIRECTIO
  • R:如何使用 R 的公式符号来紧凑地生成除选定的二次项子集之外的所有二次项?

    我想要一种紧凑地使用 R 的公式符号 或其他形式 的方法 以包含一组变量 A 到 E 之间的所有二次项 不包括 D E 交互作用 我真正的问题有更长的 A C 类型变量和 D E 类型变量列表 我写了一个小函数来检查我的工作这个帖子 谢谢
  • 比较同一个表中的两个日期范围

    我有一张每家商店的销售额表 如下所示 SQL gt select from sales ID ID STORE DATE TOTAL 1 1 2010 01 01 500 00 2 1 2010 01 02 185 00 3 1 2010
  • 这是什么{! } 在具体的代码行中意味着什么? [复制]

    这个问题在这里已经有答案了 我正在阅读一段代码 它读取 Microsoft Access 数据库架构 在其他人之间 我看到循环中的那行代码 ColName SchemaTable Rows i COLUMN NAME ToString 为什
  • 在 Inno Setup 中检索 .NET 程序集的强名称

    我需要将这些 DLL 文件安装到 GAC 中 我使用预处理器来生成 Files 这些 DLL 的节条目 我需要提供一个值StrongAssemblyName范围 所以问题 可以自动检索吗StrongAssemblyName来自 Pascal
  • $.AjaxFileUpload 在最新版本的 Chrome 版本 83.0.4103.61(官方版本)(64 位)中无法运行

    从最新版本的 Chrome 版本 83 0 4103 61 官方版本 64 位 开始 Jquery AjaxFileUpload 不起作用 如果有人有想法请帮助我 这个 AJAX 调用在旧版本的 chrome 和其他浏览器 如 firefo
  • 导航栏中的下拉菜单

    所以我正在网上学习CSS 发现这段代码有点令人困惑 因为如果我删除 dropbtn 类 输出没有任何变化 为什么它放在 li a 旁边 为什么删除对输出没有影响吗 帮助将不胜感激 谢谢 这是一段代码
  • 快速计算滑动窗口上事件的方法

    假设我有x rnorm 100000 而不是做一个1000长度滑动窗口移动平均线 我想做一个1000计算所有时间的长度滑动窗口x上面是0 2 例如 x lt rnorm 1004 start lt 1 1000 record lt list
  • 服务 JSONP 的最佳内容类型?

    我有一个 web 服务 当调用时不指定回调将返回一个 JSON 字符串application json作为内容类型 当指定回调时 它会将 JSON 字符串包装在回调函数中 因此它不再是真正有效的 JSON 我的问题是 我应该将其作为appl
  • 再次容器内联块

    看这个 我想制作一个主容器 它有 2 个子容器 左 右 各占屏幕宽度的 50 左边必须包含一张照片 右侧必须包含文本 h2 和 p 正下方 文本应该位于图像的中间 我需要它来描述商店中的产品 我正在尝试这个 div border 1px s
  • 为 Gradle 中的所有项目配置存储库

    我正在尝试为所有子项目配置存储库 我有主要的build gradle buildscript repositories mavenLocal mavenCentral google jcenter dependencies NOTE Do
  • 声明未初始化变量的更好方法

    一些 libc 函数 例如sigemptyset set mut sigset t 获取一个指向变量的指针 将其视为未初始化并初始化它 我最终得到这个代码 let mut newmask std mem uninitialized libc
  • System.Text.Json 和多态代码:不适用于 WebApi 控制器

    随着 NET 7 0 的发布 System Text Json应该支持多态代码 不幸的是 当您需要从控制器的方法返回派生类型的实例时 它似乎无法开箱即用 例如 假设以下模型 public class Base public class De