如何配置两个 JSON 序列化器并根据路由选择正确的一个

2024-04-23

我有一个使用 .Net Framework 4.7 的 ASP.NET Core Web API 项目,我正在升级到 .Net Core 3.1。我升级的原因之一是使用新的 System.Text.Json 序列化程序。

目前,我有一些基于路线的 API 版本,例如:

/api/v1/controller
/api/v2/controller

我将创建一个新的序列化器(v3)来使用新的序列化器。但问题是:我想继续在旧路由上使用 JSON.Net,以避免集成客户端出现任何可能的格式问题。

有没有一种简单的方法来配置 Asp.Net Core 以根据路由自动选择正确的 JSON 序列化器?


你可以创建自己的超级InputFormatter/OutputFormatter以便它在运行时检查条件,然后决定使用System.Text.Json or use Newtonsoft.Json动态地。

例如,我们可以检查当前的操作方法(或控制器类):

  • 如果它有一个自定义属性[UseSystemTextJsonAttribute],然后使用System.Text.Json
  • 如果它有一个自定义属性[UseNewtonsoftJsonAttribute],然后使用Newtonsoft.Json.

我创建了一个自定义的InputFormatter供您参考:

// the custom attribute
internal abstract class UseJsonAttribute : Attribute, IAsyncActionFilter
{
    public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) => next();
}
internal class UseSystemTextJsonAttribute : UseJsonAttribute { }
internal class UseNewtonsoftJsonAttribute : UseJsonAttribute { }

// Our Super Input Formatter
internal class MySuperJsonInputFormatter : TextInputFormatter
{
    public MySuperJsonInputFormatter()
    {
        SupportedEncodings.Add(UTF8EncodingWithoutBOM);
        SupportedEncodings.Add(UTF16EncodingLittleEndian);
        SupportedMediaTypes.Add("application/json");
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
    {
        var mvcOpt= context.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>().Value;
        var formatters = mvcOpt.InputFormatters;
        TextInputFormatter formatter =null; // the real formatter : SystemTextJsonInput or Newtonsoft

        Endpoint endpoint = context.HttpContext.GetEndpoint();
        if(endpoint.Metadata.GetMetadata<UseSystemTextJsonAttribute>()!= null)
        {
            formatter= formatters.OfType<SystemTextJsonInputFormatter>().FirstOrDefault();
            //formatter = formatter ?? SystemTextJsonInputFormatter
        }
        else if( endpoint.Metadata.GetMetadata<UseNewtonsoftJsonAttribute>() != null){
            // don't use `Of<NewtonsoftJsonInputFormatter>` here because there's a NewtonsoftJsonPatchInputFormatter
            formatter= (NewtonsoftJsonInputFormatter)(formatters
                .Where(f =>typeof(NewtonsoftJsonInputFormatter) == f.GetType())
                .FirstOrDefault());
        }
        else{
            throw new Exception("This formatter is only used for System.Text.Json InputFormatter or NewtonsoftJson InputFormatter");
        }
        var result = await formatter.ReadRequestBodyAsync(context,encoding);
        return result;
    }
}

internal class MySuperJsonOutputFormatter : TextOutputFormatter
{
    ... // similar to MySuperJsonInputFormatter, omitted for brevity 
}

然后在启动中配置 Json 设置/选项:

services.AddControllers(opts =>{ })
    .AddNewtonsoftJson(opts =>{ /**/ })
    .AddJsonOptions(opts =>{ /**/ });

Note AddNewtonsoftJson()将删除内置的SystemTextJsonInputFormatters。所以我们需要配置MvcOptions手动:

services.AddOptions<MvcOptions>()
    .PostConfigure<IOptions<JsonOptions>, IOptions<MvcNewtonsoftJsonOptions>,ArrayPool<char>, ObjectPoolProvider,ILoggerFactory>((opts, jsonOpts, newtonJsonOpts, charPool, objectPoolProvider, loggerFactory )=>{
        // configure System.Text.Json formatters
        if(opts.InputFormatters.OfType<SystemTextJsonInputFormatter>().Count() ==0){
            var systemInputlogger = loggerFactory.CreateLogger<SystemTextJsonInputFormatter>();
            opts.InputFormatters.Add(new SystemTextJsonInputFormatter(jsonOpts.Value, systemInputlogger));
        }
        if(opts.OutputFormatters.OfType<SystemTextJsonOutputFormatter>().Count() ==0){
            opts.OutputFormatters.Add(new SystemTextJsonOutputFormatter(jsonOpts.Value.JsonSerializerOptions));
        }
        // configure Newtonjson formatters
        if(opts.InputFormatters.OfType<NewtonsoftJsonInputFormatter>().Count() ==0){
            var inputLogger= loggerFactory.CreateLogger<NewtonsoftJsonInputFormatter>();
            opts.InputFormatters.Add(new NewtonsoftJsonInputFormatter(
                inputLogger, newtonJsonOpts.Value.SerializerSettings, charPool, objectPoolProvider, opts, newtonJsonOpts.Value
            )); 
        }
        if(opts.OutputFormatters.OfType<NewtonsoftJsonOutputFormatter>().Count()==0){
            opts.OutputFormatters.Add(new NewtonsoftJsonOutputFormatter(newtonJsonOpts.Value.SerializerSettings, charPool, opts));
        }
        opts.InputFormatters.Insert(0, new MySuperJsonInputFormatter());
        opts.OutputFormatters.Insert(0, new MySuperJsonOutputFormatter());
    });

现在应该可以正常工作了。

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

如何配置两个 JSON 序列化器并根据路由选择正确的一个 的相关文章

  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • 两个类可以使用 C++ 互相查看吗?

    所以我有一个 A 类 我想在其中调用一些 B 类函数 所以我包括 b h 但是 在 B 类中 我想调用 A 类函数 如果我包含 a h 它最终会陷入无限循环 对吗 我能做什么呢 仅将成员函数声明放在头文件 h 中 并将成员函数定义放在实现文
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • 引用的程序集自动由 Visual Studio 替换

    我有 2 个项目 一个可移植类库和一个常规单元测试项目 在可移植类库中 我使用 NuGet 来引用 Microsoft BCL 可移植包 它附带 2 个程序集 System Threading Tasks dll and System Ru
  • 如何实例化 ODataQueryOptions

    我有一个工作 简化 ODataController用下面的方法 public class MyTypeController ODataController HttpGet EnableQuery ODataRoute myTypes pub
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat

随机推荐

  • Action Filter 中的 UnitOfWork 似乎正在缓存

    我有一个使用 IoC Unity 的 MVC 3 站点 我的模型是使用 EF4 和 POCO 生成的 我正在使用操作过滤器来提交我的工作单元 public class UseUnitOfWorkAttribute ActionFilterA
  • App.config - 加密部分错误:

    我有一个对配置文件中的部分进行加密的应用程序 当我第一次尝试从配置文件中读取加密部分时 我收到一条错误消息 无法识别的属性 configProtectionProvider 请注意 属性名称区分大小写 config Configuratio
  • 如何删除选中时覆盖 UITabBarItem 的蓝色方块?

    我有一个 iPad 应用程序 Xcode 5 iOS 7 ARC 和 Storyboards 我有一个UITabBarController 并且每个场景都有一个UITabBarItem 当我点击选项卡栏项目时 它会转到正确的场景 但 当前
  • 如何列出拥有活跃订阅者的所有 pubnub 频道?

    我想列出与具有活跃订阅者的订阅密钥关联的所有频道 有没有办法用 pubnub 做到这一点 如果这有什么区别的话 我正在使用 JavaScript API PubNub 现在 API 返回与订阅键关联的频道列表 其中存在订阅者 PUBNUB
  • ASP.NET 5 MVC6 User.GetUserId() 返回错误的 ID

    我在 ASP NET 5 中有一个简单的项目 只有一个注册用户 我尝试通过扩展方法获取当前登录用户的IDGetUserId from using System Security Claims命名空间 不幸的是 这个方法返回给我不存在的ID
  • 数据表选择前5行

    您好 有什么方法可以从数据表中选择前 5 行而不进行迭代吗 我认为 你可以使用 LINQ datatable AsEnumerable Take 5
  • 编译动态内容 - AngularJS

    我正在重写这个问题 因为我认为原来的问题不太清楚 基本上 我有一个 包装器 指令 我试图将属性动态添加到包装 嵌入 元素之一 我可以让它工作 但 Angular 似乎不知道添加后的新属性 如果我使用 compile那么 Angular 确实
  • 有没有一种简单的方法对编译器输出进行颜色编码?

    gcc 或其他编译器 经常生成大量文本输出 并且很难看出错误在哪里或错过警告 我已经做了一些搜索 但还没有找到一个干净简单的解决方案来对编译器输出进行颜色编码 例如警告是黄色 错误是红色等 gcc 4 9好像添加了这个功能 https gc
  • 我可以从 FoxPro 通用字段中提取文件吗?

    我正在将 VFP 9 应用程序移植到 SQL Server VFP 应用程序有一些表 其中包含 常规 字段 查询字段时我得到一个字节数组 当我将它保存到磁盘时 我可以查看里面并看到它是一个Word文档 或者一个Paint BMP等 通过阅读
  • 规范哈夫曼编码算法

    你好 我正在尝试实现 Canonical huffman 编码 但我不明白 wiki 和 google 指南 我需要更抽象地解释 我试过这个 1 获取常规哈夫曼编码长度的代码列表 像这样 A code 110 length 3 B code
  • lambda 可以使用 *args 作为参数吗? [复制]

    这个问题在这里已经有答案了 我正在使用计算总和lambda像这样 def my func args return reduce lambda x y x y args my func 1 2 3 4 它的输出是10 但我想要一个lambda
  • 我可以在运行时选择一个特征对象而不使用 Box 吗?

    我想分支并决定在运行时在函数中使用的 Trait 实现 请参阅poly read在下面的代码示例中 Trait 对象是在 if 表达式的分支臂内部构造的 并且只需要在 if 表达式的生命周期内存在poly read但我需要Box它是因为无法
  • 无法更新 EntitySet '...',因为它有 DefiningQuery

    我将 MVC 4 和 C 4 5 与 EntityFramework 4 一起使用 我设置了一个简单的多对多表 tblAdminUser gt tblAdminUserRole lt tblAdminRole 当我尝试向管理员用户添加角色时
  • 反射真的那么慢以至于我不应该在有意义的时候使用它吗? [复制]

    这个问题在这里已经有答案了 可能的重复 NET 反射的成本有多高 https stackoverflow com questions 25458 how costly is net reflection 优雅 的解决方案problem ht
  • 如何在python中获取Windows短文件名?

    我需要从我的 python 代码中确定 Windows 短文件名 为此 我可以使用 win32api 找到解决方案 import win32api long file name C Program Files I am a file sho
  • 使 CUDA 内存不足

    我正在尝试训练网络 但我明白了 我将批量大小设置为 300 并收到此错误 但即使我将其减少到 100 我仍然收到此错误 更令人沮丧的是 在 1200 个图像上运行 10 epoch 大约需要 40 分钟 有什么建议吗 错了 我怎样才能加快这
  • Python如何将输入字符串的结果相乘[重复]

    这个问题在这里已经有答案了 我是一名正在尝试学习 Python 的编程初学者 我正在尝试完成以下练习 编写一个程序来提示用户输入小时数和每小时费率 计算总工资 这是我想出的 hours input Enter number of hours
  • Cosmos DB 中的向后分页

    我正在尝试在我的 Vue 前端上使用 c 和 cosmos 实现一个简单的分页系统 但我不确定当用户想要返回时实现分页的最佳方法 为了前进 我使用延续令牌 所以 Cosmos 知道我已经到了哪里 但我不太确定向后工作的最佳方法 或者如果用户
  • yii2 作曲家更新致命错误

    当我更新我的作曲家以添加yii2 solr扩展我的项目时 我遇到如下错误 The yiisoft yii2 composer plugin requires composer plugin api 1 0 0 this WILL break
  • 如何配置两个 JSON 序列化器并根据路由选择正确的一个

    我有一个使用 Net Framework 4 7 的 ASP NET Core Web API 项目 我正在升级到 Net Core 3 1 我升级的原因之一是使用新的 System Text Json 序列化程序 目前 我有一些基于路线的