Fast.Serialization.System.Text.Json
版本 3.5.20;目标 net8.0、net9.0、net10.0。使用 System.Text.Json,为 MVC 与工具扩展提供共同的 JSON 约定。命名空间 Fast.Serialization。
dotnet add package Fast.Serialization.System.Text.Json注册与选项作用域
AddSerialization(this IServiceCollection services, Action<Microsoft.AspNetCore.Mvc.JsonOptions> configureOptions = null) 返回服务集合。
以下为消费端 Program.cs,使用 Microsoft.NET.Sdk.Web,目标选择本页列出的 .NET 8、9 或 10,并安装上方指定包。app.Run() 表示正常宿主启动;本次文档维护不会执行它。
using Fast.Serialization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSerialization();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();当前实现先创建独立 JsonOptions,应用默认设置与传入回调,并保存到 JsonContext.SerializerOptions;向 MVC 的 services.Configure 只注册默认设置。因此,自定义回调影响静态工具选项,不自动同步到 MVC。需要 MVC 自定义行为时,另外在 AddControllers().AddJsonOptions(...) 中配置相同策略。Minimal API 的 HTTP JSON 选项也不是此处 MVC JsonOptions 的同一个类型。
默认 JSON 协议
| 项目 | 行为 |
|---|---|
| DateTime / DateTimeOffset | 默认格式 yyyy-MM-dd HH:mm:ss;该格式不保留偏移文本,不宣称自动时区往返 |
| long / long? | 输出 JSON 字符串,避免 JavaScript 数值精度丢失;读取支持数字与字符串 |
| int、decimal、double 及可空类型 | 注册对应内部转换器 |
| 枚举 | 注册普通与可空枚举转换工厂,接受名称与数值输入 |
| 引用循环 | ReferenceHandler.IgnoreCycles,不等于保留对象引用关系 |
| 数字输入 | AllowReadingFromString |
| 宽松输入 | 允许尾随逗号、跳过注释、属性名不区分大小写 |
| 输出编码 | UnsafeRelaxedJsonEscaping;JSON 放入 HTML 时仍需按 HTML 上下文转义 |
| Exception | 使用专用转换器,避免直接序列化反射成员和循环图 |
工具与转换器
JsonContext.SerializerOptions 公开读取,内部设置。以下扩展使用该上下文:
| 入口 | 参数、返回与边界 |
|---|---|
string.ToObject<T>() / string.ToObject(Type) | 先移除文本中的 ,再反序列化;输入 null 抛参数异常,非法 JSON/类型转换异常继续传播 |
object.ToJsonString() | 返回 JSON 字符串 |
IDictionary<string, object>.ToObject<T/Type>() | 经 JSON 中间表示转换,不是直接成员赋值 |
DeepCopy<T>(T source) | null 返回 default;其余经序列化/反序列化,只保留可序列化数据 |
DateJsonConverter / NullableDateJsonConverter | 日期转换,默认 yyyy-MM-dd,可指定 format |
TimeJsonConverter / NullableTimeJsonConverter | 时间显示转换 |
DataMaskingConverter(DataMaskingTypeEnum) | 字符串脱敏转换;包含姓名、账号、手机号、证件、邮箱、银行卡、地址、车牌、IP 等模式 |
不要同时引用两套 Fast.Serialization 实现来假定它们可自动切换:两个包有同名空间和同名公开类型,应用应明确选择。
对象、JSON 与字典之间的转换
在上方宿主注册完成后,业务服务可以调用这些公开扩展。以下类可直接加入同一个项目,不需要访问外部服务。
using Fast.Serialization;
public sealed class OrderSnapshot
{
public long Id { get; set; }
public string Title { get; set; } = "";
}
public sealed class SnapshotCodec
{
public string Serialize(OrderSnapshot value) => value.ToJsonString();
public OrderSnapshot Deserialize(string json) => json.ToObject<OrderSnapshot>();
public OrderSnapshot Copy(OrderSnapshot value) => value.DeepCopy();
public OrderSnapshot FromFields(IDictionary<string, object> fields) =>
fields.ToObject<OrderSnapshot>();
}long 按本包配置输出字符串;消费者不要强行当作 JavaScript number。ToObject 的 null 输入抛参数异常,格式错误或不能转换的字段由 System.Text.Json 抛出异常;JSON 字面量 null 可能返回空对象引用,尽管当前返回声明没有 nullable 标注。DeepCopy 通过一次序列化与反序列化实现,只保留可序列化内容。字典转换也经过 JSON,因此不是逐字段直接赋值,也不是无损的任意 CLR 类型转换。
来源与验证
依据 选项、注册、转换扩展。本轮未编译新增片段或运行序列化往返用例。
Decimal 数值精度
默认 decimal / decimal? 输出直接保留 decimal 值,不再经过 double 中转。只有显式指定小数位数时才执行现有 Math.Round 规则;可空值仍保持 null。JSON 数值在 JavaScript number 中是否能精确表达是另一层合同,高精度消费者应使用合适的数值表示。
