使用 C# 9 的records作为强类型ID - JSON序列化

使用 C# 9 的records作为强类型ID - 路由和查询参数

在本系列的上一篇文章中使用 C# 9 的records作为强类型ID - 路由和查询参数,我们注意到强类型ID的实体,序列化为 JSON 的时候报错了,就像这样:

{"id": {"value": 1},"name": "Apple","unitPrice": 0.8
}

不过想了一下,这样的意外也是在意料之中的,强类型ID是record类型,而不是原始类型,因此将其序列化为一个对象是有意义的,但这显然不是我们想要的……让我们看看如何解决这个问题。

System.Text.Json

在最新版本的ASP.NET Core(从3.0)中,默认的JSON序列化程序是System.Text.Json,因此让我首先介绍这种。

为了将强类型的id序列化为其值而不是对象,我们需要编写一个通用的 JsonConverter:

public class StronglyTypedIdJsonConverter<TStronglyTypedId, TValue> : JsonConverter<TStronglyTypedId>where TStronglyTypedId : StronglyTypedId<TValue>where TValue : notnull
{public override TStronglyTypedId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){if (reader.TokenType is JsonTokenType.Null)return null;var value = JsonSerializer.Deserialize<TValue>(ref reader, options);var factory = StronglyTypedIdHelper.GetFactory<TValue>(typeToConvert);return (TStronglyTypedId)factory(value);}public override void Write(Utf8JsonWriter writer, TStronglyTypedId value, JsonSerializerOptions options){if (value is null)writer.WriteNullValue();elseJsonSerializer.Serialize(writer, value.Value, options);}
}

逻辑很简单,对于直接读取 id.value, 对于反序列化,创建一个强类型id的实例,然后给它赋值。

然后在启动类中配置:

services.AddControllers().AddJsonOptions(options =>{options.JsonSerializerOptions.Converters.Add(new StronglyTypedIdJsonConverter<ProductId, int>());});

现在拿到了想要的结果:

{"id": 1,"name": "Apple","unitPrice": 0.8
}

真好!不过,还有有一个问题:我们只为添加了一个对于ProductId的转换器,但我不想为每种类型的强类型ID添加另一个转换器!我们想要一个适用于所有强类型id的转换器……,现在可以创建一个转换器工厂(ConverterFactory),就像下边这样:

public class StronglyTypedIdJsonConverterFactory : JsonConverterFactory
{private static readonly ConcurrentDictionary<Type, JsonConverter> Cache = new();public override bool CanConvert(Type typeToConvert){return StronglyTypedIdHelper.IsStronglyTypedId(typeToConvert);}public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options){return Cache.GetOrAdd(typeToConvert, CreateConverter);}private static JsonConverter CreateConverter(Type typeToConvert){if (!StronglyTypedIdHelper.IsStronglyTypedId(typeToConvert, out var valueType))throw new InvalidOperationException($"Cannot create converter for '{typeToConvert}'");var type = typeof(StronglyTypedIdJsonConverter<,>).MakeGenericType(typeToConvert, valueType);return (JsonConverter)Activator.CreateInstance(type);}
}

首先我们查看需要转换的类型,检查它是否实际上是强类型的id,然后为该类型创建特定转换器的实例,我们添加了一些缓存,避免每次都进行反射工作。

现在,我们没有添加特定的JsonConvert,只是添加了一个Factory,然后在启动文件修改,现在,我们的转换器将应用于每个强类型ID

services.AddControllers().AddJsonOptions(options =>{options.JsonSerializerOptions.Converters.Add(new StronglyTypedIdJsonConverterFactory());});

Newtonsoft.Json

如果您的项目使用的是Newtonsoft.Json进行JSON序列化,那就很简单了。

当它序列化一个值时,Newtonsoft.Json 查找一个compatible JsonConverter,如果找不到,就查找一个TypeConverter, 如果TypeConverter存在,并且可以将值转换为string,那么它把值序列化为字符串, 因为我们之前定义了 TypeConverter,Newtonsoft.Json查找到了,我得到以下结果:

{"id": "1","name": "Apple","unitPrice": 0.8
}

几乎是正确的……除了id值不应序列化为字符串,而应序列化为数字,如果id值是GUID或字符串而不是int,那就很好,则需要编写一个自定义转换器。

它和 System.Text.Json 的转换器非常相似,不同之处在于Newtonsoft.Json没有转换器工厂(ConvertFactory)的概念,相反,我们将编写一个非泛型转换器:

public class StronglyTypedIdNewtonsoftJsonConverter : JsonConverter
{private static readonly ConcurrentDictionary<Type, JsonConverter> Cache = new();public override bool CanConvert(Type objectType){return StronglyTypedIdHelper.IsStronglyTypedId(objectType);}public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer){var converter = GetConverter(objectType);return converter.ReadJson(reader, objectType, existingValue, serializer);}public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer){if (value is null){writer.WriteNull();}else{var converter = GetConverter(value.GetType());converter.WriteJson(writer, value, serializer);}}private static JsonConverter GetConverter(Type objectType){return Cache.GetOrAdd(objectType, CreateConverter);}private static JsonConverter CreateConverter(Type objectType){if (!StronglyTypedIdHelper.IsStronglyTypedId(objectType, out var valueType))throw new InvalidOperationException($"Cannot create converter for '{objectType}'");var type = typeof(StronglyTypedIdNewtonsoftJsonConverter<,>).MakeGenericType(objectType, valueType);return (JsonConverter)Activator.CreateInstance(type);}
}public class StronglyTypedIdNewtonsoftJsonConverter<TStronglyTypedId, TValue> : JsonConverter<TStronglyTypedId>where TStronglyTypedId : StronglyTypedId<TValue>where TValue : notnull
{public override TStronglyTypedId ReadJson(JsonReader reader, Type objectType, TStronglyTypedId existingValue, bool hasExistingValue, JsonSerializer serializer){if (reader.TokenType is JsonToken.Null)return null;var value = serializer.Deserialize<TValue>(reader);var factory = StronglyTypedIdHelper.GetFactory<TValue>(objectType);return (TStronglyTypedId)factory(value);}public override void WriteJson(JsonWriter writer, TStronglyTypedId value, JsonSerializer serializer){if (value is null)writer.WriteNull();elsewriter.WriteValue(value.Value);}
}

然后在启动文件中这样设置:

services.AddControllers().AddNewtonsoftJson(options =>{options.SerializerSettings.Converters.Add(new StronglyTypedIdNewtonsoftJsonConverter());});

然后,我们得到了预期的结果,输出的结果是这样:

{"id": 1,"name": "Apple","unitPrice": 0.8
}

原文作者: thomas levesque 原文链接:https://thomaslevesque.com/2020/12/07/csharp-9-records-as-strongly-typed-ids-part-3-json-serialization/

最后

欢迎扫码关注我们的公众号 【全球技术精选】,专注国外优秀博客的翻译和开源项目分享,也可以添加QQ群 897216102

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/305653.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HP LaserJet 1010卡纸解决方法

HP LaserJet 1010 系列打印机在打印过程中出现卡纸多由以下原因造成&#xff1a;1、纸盒里放入了过多的纸张或纸张位置没有放好。2、打印时使用的介质类型超出打印机的支持范围。常见卡纸位置&#xff1a;1 、硒鼓下方&#xff1b;2 、进纸口&#xff1b;3 、出纸口图 2&#x…

HP产品选件查询网站

[url]http://h18000.www1.hp.com/products/quickspecs/ProductBulletin.html#intro[/url][url]http://h18006.www1.hp.com/products/quickspecs/Division/12175.html[/url]所有的可通地此链接来查询DL380G5:[url]http://h18004.www1.hp.com/products/quickspecs/12477_div/1247…

如何使用 C# 中的 ValueTuple

Tuple 是一种数据结构&#xff0c;它由一个有序的、有限的、大小固定的、不可变的异构元素的序列组成&#xff0c;当我们说 Tuple 中的元素不可变&#xff0c;意味着其中的元素不能进行修改。ValueTuple 是在 C# 7 中被引入&#xff0c;它主要用来解决 Tuple 的两个问题。解决语…

tutte定理证明hall定理_人教社课本现低级错误?“爱因斯坦用相对论证明勾股定理”...

南方加客户端南方加客户端6月18日消息&#xff0c;近日&#xff0c;有网友在网上发帖称&#xff0c;人教版八年级下册数学自读课本中有关“爱因斯坦证明勾股定理”的内容疑似出现错误&#xff0c;此事引发网友关注&#xff0c;目前在社交平台上发酵。网友上传的课本图片据网友上…

在 “相对” 高薪面前,任何的喊冤叫屈都是苍白无力的

2021年刚开始&#xff0c;我的朋友圈就被一桩接着一桩的 “噩耗” 连番轰炸。1月1日&#xff0c;曾在《巴啦啦小魔仙》中饰演 “凌美琪” 的孙侨潞不幸去世&#xff0c;年仅25岁&#xff0c;死因是常年熬夜&#xff0c;再加上饮酒过量而导致的猝死。1月3日&#xff0c;我在网上…

在SQLSERVER企业管理器中如何创建触发器

下面将分别介绍在MS SQLServer 中如何用SQL Server 管理工具Enterprise Manager 和Transaction_SQL 来创建触发器。在创建触发器以前必须考虑到以下几个方面&#xff1a; CREATE TRIGGER 语句必须是批处理的第一个语句; 表的所有者具有创建触发器的缺省权限,表的所有者不能把该…

srv.sys蓝屏解决补丁_Win10 补丁 KB4556799 导致部分用户蓝屏死机和网络问题

IT之家5月26日消息 Windows 10 补丁 KB4556799对某些配置造成了许多新问题。除了音频问题&#xff0c;临时用户配置文件和FPS下降之外&#xff0c;Windows 10最新累积更新还导致某些用户出现蓝屏死机、崩溃和网络问题。与Windows 10更新一样&#xff0c;用户经常遇到一系列不同…

IdentityServer4(六)授权码流程原理之SPA

在【One by One系列】IdentityServer4&#xff08;四&#xff09;授权码流程中提过一句&#xff1a;“为了安全&#xff0c;IdentityServer4是带有PKCE支持的授权码模式”我们来回顾一下授权码流程&#xff08;A&#xff09;用户访问客户端&#xff0c;后者将前者导向认证服务器…

适合手机端的ckeditor样式_抖音运营干货(三):9款手机视频剪辑APP,让你轻松玩转后期!...

很多朋友想开始用手机拍视频&#xff0c;可能不知道如何剪辑&#xff01;本文将给大家介绍几款好用又方便的手机剪辑短视频工具&#xff0c;即便是零基础&#xff0c;用下面这些工具&#xff0c;你也可以轻松开始剪辑短视频。选择一款实用好用的剪辑工具很重要&#xff0c;工具…

来吧,是时候升级您的领英技术档案了

阅读此文需要2分钟&#xff08;文末有惊喜&#xff09;LinkedIn的应用之广超乎你的想象&#xff0c;包括社会招聘、公关、社群建设、销售、社交媒体营销&#xff08;包括社交广告&#xff09;以及员工宣传。LinkedIn档案不是一份简历&#xff0c;而是集客式营销&#xff08;inb…

c语言查单词小程序,【附源码】小程序初窥之简单查单词

新年假期百无聊赖&#xff0c;于是就看了一下微信小程序的开发方法&#xff0c;花了两天时间入了个门&#xff0c;这里记录一下。阅读之前&#xff0c;先确定你知道基本的 htmlcssjs 语法&#xff0c;这样就能更好地和我一样&#xff0c;以一个新手的视角来理解小程序。目标目标…

python连接mysql_Python爬虫进阶教程(八):MySQL 数据库连接

PyMySQL介绍PyMySql包含一个纯python的MySQL客户端库。PyMySQL的目标是成为MySQLdb的替代品&#xff0c;并在CPython、PyPy和IronPython上工作。版本要求python 下列之一CPython > 2.6 or > 3.3PyPy > 4.0IronPython 2.7mysql 下列之一MySQL > 4.1 (tested with on…

使用 gRPCurl 调试.NET 5的gPRC服务

介绍你用过 Curl 吗&#xff1f;这个工具允许你通过 http 来发送数据&#xff0c;现在有一个适用于gGRPC的工具&#xff0c;gRPCurl&#xff0c;在本文中&#xff0c;我将介绍如何下载安装这个工具&#xff0c;然后通过这个工具调试我们.NET 5上面的gGRC程序。安装 gRPCurlgRPC…

此 sqltransaction 已完成;它再也无法使用_手把手教你如何修眉毛,学会再也不用花钱去美容院了...

最近看到有网友在评论中询问怎么修眉毛&#xff0c;刚好小编我对修眉有一点研究&#xff0c;可能比不上专业修眉的&#xff0c;但是最少能看不是&#xff0c;今天拿出来献给大家&#xff0c;希望各位自己学会如何修眉毛&#xff0c;那样的话以后就再也不用花钱去美容院了。在此…

国产OS推广应从娃娃和体制内双管齐下

一直以来&#xff0c;国内桌面操作系统被微软垄断。究其根源&#xff0c;既有微软技术更成熟&#xff0c;软件生态丰富、服务完善、商业化水平更好等因素之外&#xff0c;也有老百姓习惯于使用Windows等因素。老百姓之所以习惯于Windows&#xff0c;则是因为破解版横行和微软早…

c语言铁路托运行李费用图,3.为铁路部门编写计算运费的程序。假设铁路托运行李,规定每张客票托运费计算方法是:行李重量不超过50kg...

满意答案wodfsdfeqd81推荐于 2018.10.08采纳率&#xff1a;51% 等级&#xff1a;12已帮助&#xff1a;5850人using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace ConsoleApplication40{class Program{static void Main(string[]…

ufo帧率测试网站_一加7游戏续航测试 满电开始玩猜猜能玩多久

业界顶级的90Hz刷新率屏幕打造沉浸式视觉体验&#xff1b;骁龙855移动平台加强性能输出&#xff1b;更加炫酷的曲面屏设计...采用无刘海式真全面屏&#xff0c;屏占比屏幕赠大的同时&#xff0c;电池容量也进一步得到提升。对于省电优化能力卓尔不群的一加7 Pro&#xff0c;让手…

并行模型Actor

并行开发时经常需要关注加锁和原子操作等一系列线程问题&#xff0c;而Actor模型内部状态由它自己维护&#xff0c;内部数据只能自己修改&#xff0c;因此Actor不需要过多关注线程问题。Actor模型Actor由状态&#xff08;State&#xff09;、邮箱&#xff08;Mailbox&#xff0…

linux cache fs,新闻|Linux 上将出现一个新的文件系统:bcachefs

这个有 5 年历史&#xff0c;由 Kent Oberstreet 创建&#xff0c;过去属于谷歌的文件系统&#xff0c;最近完成了全部关键组件。Bcachefs 文件系统自称其性能和稳定性与 ext4 和 xfs 相同&#xff0c;而其他方面的功能又可以与 btrfs 和 zfs 相媲美。主要特性包括校验、压缩、…

cad单位_CAD制图初学入门常用技巧汇总,CAD零基础也不怕!

CAD制图初学入门的小萌新们&#xff0c;最苦恼的莫过于&#xff1a;千辛万苦&#xff0c;好不容易安装的CAD软件&#xff0c;在实际CAD设计绘图中&#xff0c;居然遭遇各种问题。没有CAD制图初学入门教程、缺乏CAD大神指点、CAD图纸资源极度匮乏&#xff0c;CAD小萌新们的成长之…