Sage.JsonConverters
1.0.0.3
dotnet add package Sage.JsonConverters --version 1.0.0.3
NuGet\Install-Package Sage.JsonConverters -Version 1.0.0.3
<PackageReference Include="Sage.JsonConverters" Version="1.0.0.3" />
<PackageVersion Include="Sage.JsonConverters" Version="1.0.0.3" />
<PackageReference Include="Sage.JsonConverters" />
paket add Sage.JsonConverters --version 1.0.0.3
#r "nuget: Sage.JsonConverters, 1.0.0.3"
#:package Sage.JsonConverters@1.0.0.3
#addin nuget:?package=Sage.JsonConverters&version=1.0.0.3
#tool nuget:?package=Sage.JsonConverters&version=1.0.0.3
Sage.JsonConverters
简介
Sage.JsonConverters 是一个专为处理不规范第三方API数据而设计的安全JSON转换器库。该库提供了一系列绝对不会抛出异常的JSON转换器,能够安全地处理各种格式不一致的数据,确保程序的稳定性和可靠性。
特性
- 绝对安全:所有转换器都不会抛出异常,对于无效数据返回默认值或null
- 多类型支持:支持数字、字符串、布尔值、日期时间、对象等多种数据类型的自动转换
- 灵活转换:支持字符串数字、多种布尔值表示形式、多种日期格式等
- 可空类型支持:提供可空版本的转换器,便于区分"未设置"和"默认值"状态
- 预配置选项:提供多种预配置的JsonSerializerOptions,适用于不同场景
- 高性能:使用单例模式避免重复创建转换器实例
- 完全兼容 AOT 编译:支持原生AOT编译和源生成,提升性能
- 通用对象转换:SafeObjectConverter,专门处理第三方API的不一致格式(数组 集合)
- 空数组处理:智能处理空数组[]转换为null的场景
安装
dotnet add package Sage.JsonConverters
使用示例
基本使用
使用预配置的安全选项
using Sage.JsonConverters;
using System.Text.Json;
// 使用包含所有安全转换器的配置(推荐用于生产环境)
var options = SafeJsonConverters.CreateSafeOptions();
// 处理不规范的JSON数据
string json = """
{
"id": "123", // 字符串数字
"count": null, // null值
"price": "99.99", // 字符串价格
"isActive": "true", // 字符串布尔值
"score": "", // 空字符串
"date": "2023-12-20 14:30:00"
}
""";
var data = JsonSerializer.Deserialize<ProductData>(json, options);
// 所有字段都能正确转换,不会抛出异常
定义数据模型
public class ProductData
{
public int Id { get; set; } // 从字符串"123"转换为123
public int Count { get; set; } // 从null转换为0
public decimal Price { get; set; } // 从字符串"99.99"转换为99.99m
public bool IsActive { get; set; } // 从字符串"true"转换为true
public int Score { get; set; } // 从空字符串转换为0
public DateTime Date { get; set; } // 从字符串转换为DateTime
}
不同场景的预配置选项
1. 第三方API集成(推荐使用可空类型)
// 使用可空转换器,更容易区分"未设置"状态
var options = SafeJsonConverters.CreateNullableOptions();
public class ApiResponse
{
public int? UserId { get; set; } // null表示未设置
public decimal? Balance { get; set; } // null表示未知余额
public bool? IsVerified { get; set; } // null表示未验证
public DateTime? LastLogin { get; set; } // null表示从未登录
}
2. 财务系统(高精度计算)
// 使用decimal确保精度的财务配置
var options = SafeJsonConverters.CreateFinancialOptions();
public class FinancialData
{
public decimal? Amount { get; set; } // 使用decimal确保精度
public decimal? Tax { get; set; } // 税费计算
public int? TransactionId { get; set; } // 交易ID
public DateTime? TransactionDate { get; set; } // 交易日期
}
3. 高性能场景(仅数值转换)
// 轻量级配置,只包含数值转换器
var options = SafeJsonConverters.CreateNumberOnlyOptions();
public class MetricsData
{
public int RequestCount { get; set; }
public long ResponseTime { get; set; }
public decimal SuccessRate { get; set; }
}
4. 源生成场景(AOT兼容)
// 使用源生成的JsonSerializerContext
[JsonSerializable(typeof(ApiResponse))]
public partial class MyJsonContext : JsonSerializerContext { }
// 创建支持源生成的安全配置
var context = MyJsonContext.Default;
var options = SafeJsonConverters.CreateSafeOptionsForSourceGeneration(context);
// 在AOT场景下安全反序列化
var response = JsonSerializer.Deserialize<ApiResponse>(json, options);
5. 简单配置数据
// 基本类型转换器配置
var options = SafeJsonConverters.CreateBasicOptions();
public class ConfigData
{
public int? Port { get; set; }
public long? MaxMemory { get; set; }
public decimal? Timeout { get; set; }
public bool? EnableLogging { get; set; }
}
使用通用对象转换器处理复杂场景
处理第三方API的不一致格式
// 第三方API有时返回对象,有时返回空数组
string inconsistentJson1 = """
{
"user": {
"id": 123,
"name": "张三"
}
}
""";
string inconsistentJson2 = """
{
"user": []
}
""";
// 使用SafeObjectConverter处理
public class ApiResponse
{
[JsonConverter(typeof(SafeJsonConverters.SafeObjectConverter<User>))]
public User? User { get; set; }
}
public class User
{
public int Id { get; set; }
public string? Name { get; set; }
}
var options = SafeJsonConverters.CreateSafeOptions();
// 两种格式都能正确处理
var response1 = JsonSerializer.Deserialize<ApiResponse>(inconsistentJson1, options);
// response1.User 包含用户数据
var response2 = JsonSerializer.Deserialize<ApiResponse>(inconsistentJson2, options);
// response2.User 为 null(空数组被转换为null)
AOT场景下的对象转换
// 在AOT场景下使用SafeObjectConverter
[JsonSerializable(typeof(User))]
public partial class UserJsonContext : JsonSerializerContext { }
// 创建支持AOT的对象转换器
var userTypeInfo = UserJsonContext.Default.User;
var objectConverter = new SafeJsonConverters.SafeObjectConverter<User>(userTypeInfo);
// 手动配置转换器
var options = new JsonSerializerOptions();
options.Converters.Add(objectConverter);
使用特性标注的自动转换
using System.Text.Json.Serialization;
using Sage.JsonConverters;
// 在属性上直接使用转换器特性
public class ProductInfo
{
[JsonConverter(typeof(SafeJsonConverters.SafeIntConverter))]
public int ProductId { get; set; }
[JsonConverter(typeof(SafeJsonConverters.SafeNullableDecimalConverter))]
public decimal? Price { get; set; }
[JsonConverter(typeof(SafeJsonConverters.SafeNullableBoolConverter))]
public bool? IsAvailable { get; set; }
[JsonConverter(typeof(SafeJsonConverters.SafeNullableDateTimeConverter))]
public DateTime? CreatedDate { get; set; }
// 使用SafeObjectConverter处理可能为空数组的对象
[JsonConverter(typeof(SafeJsonConverters.SafeObjectConverter<ProductDetails>))]
public ProductDetails? Details { get; set; }
// 普通属性不需要特殊处理
public string? Name { get; set; }
public string? Description { get; set; }
}
public class ProductDetails
{
public string? Category { get; set; }
public string? Brand { get; set; }
public int? Weight { get; set; }
}
// 使用时不需要特殊配置
string json = """
{
"productId": "12345",
"price": "99.99",
"isAvailable": "true",
"createdDate": "2023-12-20 14:30:00",
"details": {
"category": "电子产品",
"brand": "示例品牌",
"weight": "500"
},
"name": "示例产品",
"description": null
}
""";
// 处理空数组的情况
string jsonWithEmptyArray = """
{
"productId": "12345",
"price": "99.99",
"isAvailable": "true",
"createdDate": "2023-12-20 14:30:00",
"details": [],
"name": "示例产品",
"description": null
}
""";
// 直接反序列化,标注的属性会自动使用安全转换器
var product1 = JsonSerializer.Deserialize<ProductInfo>(json);
// product1.Details 包含详细信息
var product2 = JsonSerializer.Deserialize<ProductInfo>(jsonWithEmptyArray);
// product2.Details 为 null(空数组被安全转换为null)
源生成场景下的SafeObjectConverter特性标注
当使用源生成(AOT兼容)时,SafeObjectConverter的特性标注需要特殊处理:
// 1. 定义JsonSerializerContext
[JsonSerializable(typeof(ProductInfo))]
[JsonSerializable(typeof(ProductDetails))] // 必须包含嵌套类型
public partial class ProductJsonContext : JsonSerializerContext { }
// 2. 数据模型定义(与上面相同)
public class ProductInfo
{
[JsonConverter(typeof(SafeJsonConverters.SafeIntConverter))]
public int ProductId { get; set; }
[JsonConverter(typeof(SafeJsonConverters.SafeNullableDecimalConverter))]
public decimal? Price { get; set; }
// 在源生成场景下,SafeObjectConverter需要特殊处理
// 注意:特性标注在源生成中可能不完全支持,建议使用手动配置
[JsonConverter(typeof(SafeJsonConverters.SafeObjectConverter<ProductDetails>))]
public ProductDetails? Details { get; set; }
public string? Name { get; set; }
}
public class ProductDetails
{
public string? Category { get; set; }
public string? Brand { get; set; }
public int? Weight { get; set; }
}
// 3. 推荐的源生成使用方式(手动配置转换器)
var context = ProductJsonContext.Default;
var options = SafeJsonConverters.CreateSafeOptionsForSourceGeneration(context);
// 为SafeObjectConverter添加JsonTypeInfo支持
var detailsTypeInfo = ProductJsonContext.Default.ProductDetails;
var objectConverter = new SafeJsonConverters.SafeObjectConverter<ProductDetails>(detailsTypeInfo);
options.Converters.Add(objectConverter);
// 使用配置进行反序列化
var product = JsonSerializer.Deserialize<ProductInfo>(json, options);
重要说明:
- 在源生成场景下,推荐使用手动配置而非特性标注
- 必须在JsonSerializerContext中包含所有相关类型
- SafeObjectConverter需要JsonTypeInfo参数以支持AOT
手动配置转换器
// 自定义配置JsonSerializerOptions
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
// 添加特定的转换器
options.Converters.Add(SafeJsonConverters.NullableInt);
options.Converters.Add(SafeJsonConverters.NullableDecimal);
options.Converters.Add(SafeJsonConverters.NullableBool);
options.Converters.Add(SafeJsonConverters.NullableDateTime);
支持的数据类型和转换规则
整数转换 (int/int?)
- 数字:直接转换,处理溢出
- 字符串数字:"123" → 123
- 空字符串/null:转换为0(可空版本返回null)
- 无效格式:返回0(可空版本返回null)
长整数转换 (long/long?)
- 支持64位整数范围
- 转换规则与int类似
浮点数转换 (double/double?)
- 数字:直接转换
- 字符串数字:"99.99" → 99.99
- 特殊值:处理NaN、Infinity等
- 使用InvariantCulture:确保跨文化兼容性
高精度数值转换 (decimal/decimal?)
- 推荐用于财务计算:确保精度不丢失
- 字符串转换:"123.456789" → 123.456789m
- 货币格式支持:处理各种货币表示
布尔值转换 (bool/bool?)
- 标准布尔值:true/false
- 数字:非零为true,0为false
- 字符串:支持多种格式
- "true"/"false"
- "yes"/"no"
- "on"/"off"
- "y"/"n"
- "1"/"0"
- 大小写不敏感
日期时间转换 (DateTime/DateTime?)
支持多种日期格式:
- ISO 8601:2023-12-20T14:30:00Z
- 标准格式:2023-12-20 14:30:00
- 仅日期:2023-12-20
- 美式格式:12/20/2023
- 欧式格式:20/12/2023
- 中文格式:2023/12/20
通用对象转换 (SafeObjectConverter)
- 正常对象:{} → 正常反序列化
- 空数组:[] → null(可配置)
- null值:null → null
- 字符串/其他类型:安全处理,返回null
- AOT支持:可传入JsonTypeInfo实现AOT兼容
- 异常安全:绝对不会抛出异常
在ASP.NET Core中使用
// Program.cs
using Sage.JsonConverters;
var builder = WebApplication.CreateBuilder(args);
// 配置JSON选项
builder.Services.ConfigureHttpJsonOptions(options =>
{
var safeOptions = SafeJsonConverters.CreateSafeOptions();
options.SerializerOptions.Converters.Clear();
foreach (var converter in safeOptions.Converters)
{
options.SerializerOptions.Converters.Add(converter);
}
options.SerializerOptions.PropertyNameCaseInsensitive = true;
options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
var app = builder.Build();
处理复杂的第三方API响应
// 第三方API返回的不规范JSON
string apiResponse = """
{
"user_id": "12345",
"balance": null,
"is_premium": "1",
"last_login": "",
"settings": {
"notifications": "true",
"theme": "dark",
"timeout": "30"
}
}
""";
var options = SafeJsonConverters.CreateNullableOptions();
var userData = JsonSerializer.Deserialize<UserData>(apiResponse, options);
public class UserData
{
public int? UserId { get; set; } // 从"12345"转换为12345
public decimal? Balance { get; set; } // null保持为null
public bool? IsPremium { get; set; } // 从"1"转换为true
public DateTime? LastLogin { get; set; } // 空字符串转换为null
public UserSettings? Settings { get; set; }
}
public class UserSettings
{
public bool? Notifications { get; set; } // 从"true"转换为true
public string? Theme { get; set; } // 字符串保持不变
public int? Timeout { get; set; } // 从"30"转换为30
}
最佳实践
选择合适的配置:
- 生产环境推荐使用
CreateSafeOptions() - 第三方API集成推荐使用
CreateNullableOptions() - 财务系统推荐使用
CreateFinancialOptions() - AOT场景推荐使用
CreateSafeOptionsForSourceGeneration()
- 生产环境推荐使用
数据验证:虽然转换器不会抛出异常,但仍建议在业务逻辑中验证关键数据
性能优化:转换器使用单例模式,可以安全地重复使用配置选项
错误处理:对于关键业务数据,建议使用可空版本的转换器以便区分"未设置"状态
测试:在集成第三方API时,使用各种边界情况测试转换器的行为
对象转换:对于可能返回空数组的第三方API,使用SafeObjectConverter处理不一致格式
AOT兼容性:在原生AOT场景下,优先使用源生成和JsonTypeInfo版本的转换器
版本历史
v1.0.0.2 (最新版本)
- ✨ 新增
SafeObjectConverter<T>通用对象转换器 - ✨ 支持空数组
[]转换为null的场景 - ✨ 新增
CreateSafeOptionsForSourceGeneration()方法支持源生成 - 🚀 完全兼容原生AOT编译
- 📝 完善文档和使用示例
v1.0.0.1
- 🎉 首次发布
- ✨ 提供基础数据类型的安全转换器
- ✨ 支持可空类型转换
- ✨ 提供多种预配置选项
许可证
本项目采用 Apache 2.0 许可证。详情请参阅 LICENSE 文件。
贡献
欢迎提交问题报告和改进建议。如果您想贡献代码,请提交拉取请求。
作者
- LiuPengLai - 甲壳虫科技
欢迎提交问题和功能请求。 QQ Group: 1054304346
| 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.
支持NET10