第一次接触 .Net 是2012年刚进入大学时,之后也一直作为桌面编程语言来使用。工作后,刚开始项目上更多的是使用 PHP 来快速开发,直到去年某次突然发现 .NET 竟不知道什么时候开始不仅跨平台还开源了。
看着微软的官方文档异常激动,按捺不住,拿一个项目上手试了一下,那个时候啥也不懂,嫌弃 JwtBearer 给我引了一大堆 dll,然后自己看文档用中间件造了轮子;而且那个时候我不知道有 EF core,也不懂什么 DBfirst,直接刀耕火种,手写 SQL,把自己累的够呛。当然在各种项目的使用中也或多或少出现了各种问题,现将使用 Json 格式相关的内容总结下来以供大家参考。
中文 Unicode 和 字符转义 问题
中文 Unicode 这个问题在 ASP.NET Core 的返回中正常并不会出现,而是在控制台中使用
JsonSerializer.Serialize
将对象转为 json 时发生,解决方案也很简单,只需要通过 JsonSerializerOptions
[1]
设置要在转义字符串时使用的编码器即可。
var options = new JsonSerializerOptions { Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) };
在不需要转移特殊符号的场景下,使用
JsonSerializer.Serialize
时,传入上方的
options
即可。
当你前往官网仔细研究这个
UnicodeRanges
的时候,你会发现 Unicode 块竟然还有
YijingHexagramSymbols
易经八卦符号 ䷀(乾)䷁(坤)等共六十四卦,说实话我还是第一次发现,遥想当年汉字输入都是问题。八卦是我们东方人得天独厚的文化,“易有太极,是生两仪,两仪生四象,四象生八卦。” 八卦亦可用二进制表示,然后通过 8x8 的矩阵就成了易经六十四卦。
字符转义问题在 ASP.NET Core 的返回中正常并不会出现,而是在控制台中使用时,这个和上一个问题类似。若要最大程度地减少转义(肯定是已含上面的了),可以使用
JavaScriptEncoder.UnsafeRelaxedJsonEscaping
。
var options = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
这里需要注意的是,使用该配置后,此时你需要额外注意 XSS 或信息泄露攻击的可能。
另外,在非业务场景下,只是为了展示测试时,我们可以设置
JsonSerializerOptions
的
WriteIndented
为
true
,这样 JSON 的返回只是整理好格式的易读形式。
以上问题更详细的说明,可以查看微软官方的文档 如何使用 System.Text.Json 自定义字符编码
[2]
。
时间格式化的问题,主要是国情问题和能否直接显示给客户的问题。若是有国际化的问题,那就要额外再加一些其他逻辑处理了。其实我觉得这个丢给前端也挺好嘛,嘿嘿嘿。
现在我们在这样一个接口:
app.MapGet("/test", () =>
return new
now = DateTime.Now,
time = TimeOnly.FromDateTime(DateTime.Now),
day = DateOnly.FromDateTime(DateTime.Now)
需要注意的是,当前 .NET 6 是不支持 TimeOnly 和 DateTime 直接返回的,需要 .ToString()
,直接返回是会报下面的错误的:
System.NotSupportedException: Serialization and deserialization of 'System.TimeOnly' instances are not supported.
转为字符后输出结果如下:
"now": "2022-10-30T14:43:02.0027311+08:00",
"time": "14:43",
"day": "2022/10/30"
在 .NET 7 的当前预览版中,已经支持了 TimeOnly 和 DateOnly 的直接序列化 https://github.com/dotnet/runtime/pull/69160。
更改为 .NET7 后,其输出结果如下:
"now": "2022-10-30T14:53:22.095974+08:00",
"time": "14:53:22.0959758",
"day": "2022-10-30"
可以看到返回的差异还是挺大的,如果返回不合你的心意,怎么能让其统一呢?这里就需要用到注册的用户定义的转换器,下面提供三个时间处理的样例,大家可以按需求复制粘贴,其实代码都类似的。
处理日期时间的:
using System.Text.Json;
using System.Text.Json.Serialization;
internal class JsonDateTimeConverter : JsonConverter<DateTime>
public string Format { get; set; } = "yyyy-MM-dd HH:mm:ss";
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => DateTime.Parse(reader.GetString());
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToString(this.Format));
处理日期的:
using System.Text.Json;
using System.Text.Json.Serialization;
internal class JsonDateOnlyConverter : JsonConverter<DateOnly>
public string Format { get; set; } = "yyyy-MM-dd";
public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => DateOnly.Parse(reader.GetString());
public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToString(this.Format));
处理时间的:
using System.Text.Json;
using System.Text.Json.Serialization;
internal class JsonTimeOnlyConverter : JsonConverter<TimeOnly>
public string Format { get; set; } = "HH:mm:ss";
public override TimeOnly Read(ref Utf8JsonReader reader,Type typeToConvert, JsonSerializerOptions options) => TimeOnly.Parse(reader.GetString());
public override void Write(Utf8JsonWriter writer, TimeOnly value,JsonSerializerOptions options) => writer.WriteStringValue(value.ToString(this.Format));
使用时可以直接引用,也可以设置格式方式。
builder.Services.Configure<JsonOptions>(options => {
options.SerializerOptions.Converters.Add(new JsonDateTimeConverter() { Format = "yyyy年MM月dd日 HH:mm:ss" });
options.SerializerOptions.Converters.Add(new JsonDateOnlyConverter());
options.SerializerOptions.Converters.Add(new JsonTimeOnlyConverter());
输出结果:
"now": "2022年10月30日 15:12:54",
"time": "15:12:54",
"day": "2022-10-30"
循环引用,主要报错信息如下:
System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 64.
以下代码是为了复现而复现,当然实际情况我们遇到的话,往往是不经意间就出现了。
internal class User{
public string Name {get;set;}
public Role Role {get;set;}
internal class Role{
public string RoleName {get;set;}
public User[] Users {get;set;}
app.MapGet("/test", () =>
var role = new Role(){RoleName = "小组长"};
var user = new User(){Name = "王小明"};
user.Role = role;
role.Users = new User[]{user};
return new {
user = user
如果循环的只是为了编码查找方便,或者说此接口没必要输出的情况下,可以直接标记为忽略,不进行 json 输出。
internal class Role
public string RoleName { get; set; }
[JsonIgnore]
public User[] Users { get; set; }
ASP.NET 中,需要配置:
builder.Services.Configure<JsonOptions>(options => {
options.SerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
控制台程序或命令行打印时:
var options = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.IgnoreCycles };
在这里还是要再感谢一下杨老师,还好在大学的时候某次见面会加了微信,在他朋友圈看到在推录制的 .NET 6教程[3] 。不然说不定目前我还是在刀耕火种阶段,哈哈哈……
References
[1]
JsonSerializerOptions: https://docs.microsoft.com/zh-cn/dotnet/api/system.text.json.jsonserializeroptions?view=net-6.0
[2]
System.Text.Json 自定义字符编码: https://learn.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json/character-encoding
[3]
.NET 6教程: https://www.bilibili.com/video/BV1pK41137He/
本文主要总结介绍 .NET 中的对 Json 数据使用在使用过程中的关于编码、循环引用、时间格式化的一些问题背景第一次接触 .Net 是2012年刚进入大学时,之后也一直作为桌面编程语言来使用。工作后,刚开始项目上更多的是使用 PHP 来快速开发,直到去年某次突然发现 .NET 竟不知道什么时候开始不仅跨平台还开源了。看着微软的官方文档异常激动,按捺不住,拿一个项目上手试了一下,那个时候啥也不懂,...
Json.NET 是 .NET 平台中非常流行的高性能 JSON 处理框架。仅通过一行代码即可实现 JSON 序列化和反序列化:序列化 JSONProduct product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string...
序列化里的xml,soap,binary在上一篇文章里面已经说过了,这篇主要说json。
json是目前非常流行的一种序列化数据的方式,很多api都采用的是json,结构简洁,容易理解,适用性强,逐渐代替之前的xml在各个数据传输和存储的领域的使用,比如VS Code的配置文件:
json格式的结构很简单,分号隔开的键值堆构成,逗号隔开,{}表示对象,[]表示集合,值可以是数字,字符串...
Json 在 .net里就是字符串,但有三方类库(如:Newtonsoft.Json也称Json.net)用于处理JSON。
【更新】在 .net core 中对 json 有原生支持,参见命名控件System.Text.Json(System.Text.Json.dll)
一般是两种方式来用:
1、固定结构...
public void ProcessRequest(HttpContext context)
context.Response.ContentType = "text/plain";
//--构建json格式数据
//stri
写缩进,容易阅读JSON
JSON和XML之间进行转换
支持: .NET 2, .NET 3.5, .NET 4, .NET 4.5, Silverlight, Windows Phone and Windows 8 Store
Json.NET has different libaries for the various .NET Framework versions.
-Net45:
.NET latest (4.5)
-Net40:
.NET 4.0
-Net35:
.NET 3.5
-Net20:
.NET 2.0
-WinRT:
Windows 8 Store
-Portable45:
.NET 4.5, Windows Phone 8, Windows 8 Store
-Portable40:
.NET 4.0, Windows Phone 7, Windows 8 Store, Silverlight 4
Notes:
Microsoft stopped support for the Compact Framework in Visual Studio 2010.
For a Compact Framework 3.5 build download Json.NET 3.5.
For a Silverlight 3.0 build download Json.NET 3.5.
Microsoft Visual Studio 2010 重新生成解决方案的一些警告处理
警告 2 预定义类型“System.Action”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework
\v4.0\mscorlib.dll”中的定义 ClassLibrary1
警告 3 预定义类型“System.Action”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework
\v4.0\mscorlib.dll”中的定义 ClassLibrary1
警告 4 预定义类型“System.Action”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework
\v4.0\mscorlib.dll”中的定义 ClassLibrary1
警告 5 预定义类型“System.Action”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework
\v4.0\mscorlib.dll”中的定义 ClassLibrary1
警告 6 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework
\v4.0\mscorlib.dll”中的定义 ClassLibrary1
警告 7 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework
\v4.0\mscorlib.dll”中的定义 ClassLibrary1
警告 8 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework
\v4.0\mscorlib.dll”中的定义 ClassLibrary1
警告 9 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework
\v4.0\mscorlib.dll”中的定义 ClassLibrary1
警告 10 预定义类型“System.Func”是在全局别名的多个程序集中定义的;将使用“c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework
\v4.0\mscorlib.dll”中的定义 ClassLibrary1
问题原因:检查程序发现,由于项目中引用了Newtonsoft.Json.Net20,从而造成系统的类重名(项目FRAMEWORK的版本4.0)。
Newtonsoft.Json.Net 包括: .NET 2, .NET 3.5, .NET 4, .NET 4.5, Silverlight, Windows Phone and Windows 8 Store,所有dll文件和源码,有需要的同学可以直接下载。
个人网站多多支持:www.mlyuansu.com
我在网上搜了好多的文章,讲了很多的方法。但是无一例外的都看不懂...可能是因为我在这方面是个白痴吧...
所幸的是,我搜到了一个博客,写的很是清晰,比我之前看的大片文章写的好多了,在这里:http://blog.csdn.net/miaozhenzhong/article/details/52585726
写这篇文章的大佬也不知道是谁,反正甚是感谢。
看了上面十分清晰的文...
.NET提供了一个类库System.Text.Json来生成json。我们可以使用System.Text.Json.JsonSerializer类的Serialize方法将对象序列化为json字符串,或者使用System.Text.Json.JsonDocument类来创建json文档并将其保存为文件。以下是一个示例代码:
```csharp
using System;
using System.Text.Json;
class Program
static void Main(string[] args)
var obj = new {
Name = "Alice",
Age = 28,
Occupation = "Software Engineer"
var jsonStr = JsonSerializer.Serialize(obj);
Console.WriteLine(jsonStr);
这个程序将输出以下内容:
```json
"Name": "Alice",
"Age": 28,
"Occupation": "Software Engineer"