Sage.JsonConverters
2.0.0
dotnet add package Sage.JsonConverters --version 2.0.0
NuGet\Install-Package Sage.JsonConverters -Version 2.0.0
<PackageReference Include="Sage.JsonConverters" Version="2.0.0" />
<PackageVersion Include="Sage.JsonConverters" Version="2.0.0" />
<PackageReference Include="Sage.JsonConverters" />
paket add Sage.JsonConverters --version 2.0.0
#r "nuget: Sage.JsonConverters, 2.0.0"
#:package Sage.JsonConverters@2.0.0
#addin nuget:?package=Sage.JsonConverters&version=2.0.0
#tool nuget:?package=Sage.JsonConverters&version=2.0.0
Sage.JsonConverters
Sage.JsonConverters 是一个面向 System.Text.Json 的轻量级安全转换器库。
它专注于一件事:提供一组可按需注册的基础类型转换器,在第三方接口返回空字符串、字符串数字、字符串布尔值或不够规范的时间字符串时,尽量避免反序列化异常。
设计目标
- 轻量:只提供基础转换器,不内置库级全局配置工厂。
- 简单:所有能力都围绕显式注册 converter 展开。
- 高效:优先使用
TryParse/TryGetXxx路径,避免不必要的异常流程。 - AOT 友好:不依赖对象转换反射工厂,也不依赖运行时动态代码生成逻辑。
安装
dotnet add package Sage.JsonConverters
快速开始
最常见的方式是在局部创建 JsonSerializerOptions,只注册当前模型需要的转换器。
using Sage.JsonConverters;
using System.Text.Json;
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
options.Converters.Add(new SafeJsonConverters.SafeIntConverter());
options.Converters.Add(new SafeJsonConverters.SafeBoolConverter());
options.Converters.Add(new SafeJsonConverters.SafeNullableDateTimeOffsetConverter());
var payload = JsonSerializer.Deserialize<OrderPayload>(
"""
{
"id": "123",
"isPaid": "true",
"changedAt": ""
}
""",
options);
public sealed class OrderPayload
{
public int Id { get; set; }
public bool IsPaid { get; set; }
public DateTimeOffset? ChangedAt { get; set; }
}
上面的行为如下:
"123"会被解析为123"true"会被解析为true""会被解析为null
常见注册方式
1. 局部 JsonSerializerOptions
这是最推荐的方式,影响范围最小,也最容易控制具体模型的兼容规则。
using Sage.JsonConverters;
using System.Text.Json;
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
options.Converters.Add(new SafeJsonConverters.SafeNullableIntConverter());
options.Converters.Add(new SafeJsonConverters.SafeNullableDecimalConverter());
options.Converters.Add(new SafeJsonConverters.SafeNullableBoolConverter());
options.Converters.Add(new SafeJsonConverters.SafeNullableDateTimeOffsetConverter());
var payload = JsonSerializer.Deserialize<InvoicePayload>(
"""
{
"id": "123",
"amount": "99.95",
"isPaid": "true",
"changedAt": ""
}
""",
options);
public sealed class InvoicePayload
{
public int? Id { get; set; }
public decimal? Amount { get; set; }
public bool? IsPaid { get; set; }
public DateTimeOffset? ChangedAt { get; set; }
}
2. 按属性标注转换器
如果只有少数字段需要放宽反序列化规则,可以直接在属性上标注 [JsonConverter]。
using Sage.JsonConverters;
using System.Text.Json.Serialization;
public sealed class ProductPayload
{
[JsonConverter(typeof(SafeJsonConverters.SafeIntConverter))]
public int Id { get; set; }
[JsonConverter(typeof(SafeJsonConverters.SafeNullableDecimalConverter))]
public decimal? Price { get; set; }
[JsonConverter(typeof(SafeJsonConverters.SafeNullableDateTimeOffsetConverter))]
public DateTimeOffset? ChangedAt { get; set; }
}
3. 业务项目自己封装常用配置
库本身不提供 Create*Options() 工厂方法,但业务项目可以按自己的边界封装一层。
using Sage.JsonConverters;
using System.Text.Json;
public static class ApiJsonOptions
{
public static JsonSerializerOptions Create()
{
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
options.Converters.Add(new SafeJsonConverters.SafeNullableIntConverter());
options.Converters.Add(new SafeJsonConverters.SafeNullableBoolConverter());
options.Converters.Add(new SafeJsonConverters.SafeNullableDateTimeOffsetConverter());
return options;
}
}
4. Web API 全局配置
虽然库本身不内置全局配置入口,但你可以在 ASP.NET Core / Web API 项目里手动全局注册这些 converter。
using Sage.JsonConverters;
using System.Text.Json;
using System.Text.Json.Serialization;
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
options.SerializerOptions.PropertyNameCaseInsensitive = true;
options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.SerializerOptions.WriteIndented = builder.Environment.IsDevelopment();
options.SerializerOptions.IncludeFields = true;
options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.SerializerOptions.Converters.Add(new SafeJsonConverters.SafeNullableDateTimeOffsetConverter());
options.SerializerOptions.Converters.Add(new SafeJsonConverters.SafeNullableIntConverter());
options.SerializerOptions.Converters.Add(new SafeJsonConverters.SafeNullableBoolConverter());
});
全局注册适合统一处理来自外部系统的脏数据,但它会影响整个 Web API 的输入行为。对于只在少数字段上需要放宽规则的场景,仍然更推荐属性标注或局部 options。
AOT / Source Generation
库中的转换器本身不依赖反射工厂或动态代码生成,可以安全用于 AOT 场景。
如果你的业务模型使用 System.Text.Json 源生成,推荐直接在对应属性上标注标准的 [JsonConverter(typeof(...))] 特性,让源生成元数据在编译期就固定下来。
using Sage.JsonConverters;
using System.Text.Json;
using System.Text.Json.Serialization;
public sealed class EventPayload
{
[JsonConverter(typeof(SafeJsonConverters.SafeNullableIntConverter))]
public int? Id { get; set; }
[JsonConverter(typeof(SafeJsonConverters.SafeNullableDateTimeOffsetConverter))]
public DateTimeOffset? ChangedAt { get; set; }
}
[JsonSerializable(typeof(EventPayload))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}
var payload = JsonSerializer.Deserialize(
"""{"Id":"123","ChangedAt":""}""",
AppJsonSerializerContext.Default.EventPayload);
支持的转换器
数值
SafeIntConverterSafeNullableIntConverterSafeLongConverterSafeNullableLongConverterSafeDoubleConverterSafeNullableDoubleConverterSafeDecimalConverterSafeNullableDecimalConverter
规则概览:
- 字符串数字使用
InvariantCulture解析 - 无效输入返回默认值或
null - 超范围数值会按目标类型进行边界收敛
示例:
SafeIntConverter:"123"→123,""→0SafeNullableIntConverter:"123"→123,""→nullSafeDoubleConverter:"12.5"→12.5SafeNullableDecimalConverter:"99.95"→99.95m
布尔
SafeBoolConverterSafeNullableBoolConverter
支持的字符串值包括:
true/false1/0yes/noon/offy/n
示例:
SafeBoolConverter:"yes"→trueSafeNullableBoolConverter:""→null
时间
SafeDateTimeConverterSafeNullableDateTimeConverterSafeDateTimeOffsetConverterSafeNullableDateTimeOffsetConverter
规则概览:
null、空字符串、空白字符串会返回默认值或null- 仅支持固定的、无歧义的日期格式与 round-trip 格式
- 不再接受
MM/dd/yyyy、dd/MM/yyyy这类有歧义的格式 - 序列化时使用
Utf8JsonWriter内置的 ISO 8601 写法,保留时区与小数秒信息 DateTimeOffset无时区输入按 UTC 解释
示例:
SafeNullableDateTimeConverter:""→nullSafeNullableDateTimeOffsetConverter:""→nullSafeDateTimeOffsetConverter:"2024-01-02T03:04:05+08:00"→ 对应DateTimeOffset
2.0 迁移指引
2.0.0 包含以下 breaking changes:
- 删除所有
Create*Options()预设方法 - 删除静态单例字段,改为显式
newconverter - 删除
SafeObjectConverter<T>与对象转换工厂 - 新增
DateTimeOffset/DateTimeOffset?支持 DateTime不再接受有歧义的日期格式
如果你从 1.x 升级到 2.0,通常需要这样调整:
旧写法:
SafeJsonConverters.NullableInt新写法:
new SafeJsonConverters.SafeNullableIntConverter()旧写法:
SafeJsonConverters.CreateSafeOptions()新写法:在业务侧手动创建
JsonSerializerOptions并按需注册 converter
许可证
Apache 2.0
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
2.0.0: 移除预设 JsonSerializerOptions 与对象转换器,新增 DateTimeOffset 支持,并统一为按需注册的使用方式。